分类:
2008-10-29 16:07:01
3.9 i/o efficiency
在重复的读取文件中的数据的时候,每次读取的数据量大小如果接近磁盘的block_size的话,效率是比较高的。
3.13 sync, fsync, fdatasync
1. Sync调用时,只是告知kernel对所有的磁盘缓冲中修改过的页面要被调度写回磁盘,但sync返回时,并不意味着写操作已经完成。那样的话sync可能会等很长时间。
还有一个sync命令,他也会调用sync函数。
2. Fsync(int fd)只对一个file descriptor进行该操作,并且返回时,所有写操作已经完成。
3. fdatasync(int fd)只对一个文件的一部分数据进行该操作。
系统多用一个守护进程来定期调用sync。
3.14 fcntl函数
#include
int fcntl(int filedes, int cmd, ... /* int arg */ );
Returns: depends on cmd if OK (see following), 1 on error
功能:
The fcntl function is used for five different purposes.
1.Duplicate an existing descriptor (cmd = F_DUPFD)
2.Get/set file descriptor flags (cmd = F_GETFD or F_SETFD)
3.Get/set file status flags (cmd = F_GETFL or F_SETFL)
4.Get/set asynchronous I/O ownership (cmd = F_GETOWN or F_SETOWN)
5.Get/set record locks (cmd = F_GETLK, F_SETLK, or F_SETLKW)
1.File descriptor的flags中的close-on-exec flag: 我们在进程A中打开了文件f, 当文件f的file descriptor的close-on-exec flag被设置的时候,当我们执行exec系统调用时,进程A的代码段,数据段等都被新的程序代替,而且进程A中打开的文件也会被关闭。如果close-on-exec没有设置,在exec后,旧进程打开的文件就不会被关闭,即file descriptor依然有效,好处是一些daemon经常要fork然后exec一些子进程,这样如果不设置close-on-exec,这些子进程都会共享父进程的文件。
2.File status flag包括:
O_RDONLY |
open for reading only |
O_WRONLY |
open for writing only |
O_RDWR |
open for reading and writing |
O_APPEND |
append on each write |
O_NONBLOCK |
Non-blocking mode |
O_SYNC |
wait for writes to complete (data and attributes) |
O_DSYNC |
wait for writes to complete (data only) |
O_RSYNC |
synchronize reads and writes |
O_FSYNC |
wait for writes to complete (FreeBSD and Mac OS X only) |
O_ASYNC |
asynchronous I/O (FreeBSD and Mac OS X only) |
例子:读取一个file descriptor的status flag并打印出来。
$ ./a.out 0 < /dev/tty
read only
$ ./a.out 1 > temp.foo (输出被重定向到temp.foo中)
$ cat temp.foo
write only
$ ./a.out 2 2>>temp.foo
write only, append
$ ./a.out 5 5<>temp.foo
read write
上述例子的代码:
#include "apue.h"
#include
int
main(int argc, char *argv[])
{
int val;
if (argc != 2)
err_quit("usage: a.out ");
if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
err_sys("fcntl error for fd %d", atoi(argv[1]));
switch (val & O_ACCMODE) {
case O_RDONLY:
printf("read only");
break;
case O_WRONLY:
printf("write only");
break;
case O_RDWR:
printf("read write");
break;
default:
err_dump("unknown access mode");
}
if (val & O_APPEND)
printf(", append");
if (val & O_NONBLOCK)
printf(", nonblocking");
#if defined(O_SYNC)
if (val & O_SYNC)
printf(", synchronous writes");
#endif
#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC)
if (val & O_FSYNC)
printf(", synchronous writes");
#endif
putchar('\n');
exit(0);
}
Linux ext2不遵从O_SYNC的定义
O_SYNC在linux ext2 file system上并不能起到作用,即如果以这个模式打开文件,我们调用write后,write返回后,并不能保证数据已经写到了磁盘上,而仅仅是将该数据放入了一个将要被写到磁盘上的队列中。因此对使用O_SYNC和不使用 O_SYNC打开的文件进行write操作,在耗时上没什么区别,这个我也测试过。
而使用sync(), sync(fd)的效果接近,即可以保证数据写到了磁盘上了。
#include
#include
#include
#define BUFFSIZE 4096
int main()
{
int n=0;
char buf[BUFFSIZE];
#if 0
int flags = fcntl( STDOUT_FILENO, F_GETFL, 0 );
if( flags < 0 )
{
printf("get file STDOUT_FILENO flag error!\n ");
return -1;
}
flags |= O_SYNC;
int ret = fcntl( STDOUT_FILENO, F_SETFL, flags );
if( ret < 0 )
{
printf("set flag error on file STDOUT_FILENO\n");
return -1;
}
#endif
while( (n = read( STDIN_FILENO, buf, BUFFSIZE )) > 0 )
{
if( write( STDOUT_FILENO, buf, n ) != n )
{
printf("write error\n");
break;
}
}
// fsync(STDOUT_FILENO);
// sync();
return 0;
}
上面代码中,使用#if 0包括的部分就是设置O_SYNC的代码段,是否设置O_SYNC效果是一样的。且fsync()和sync()的效果也一样。不过都比O_SYNC耗时多。
3.15 ioctl 函数
Ioctl函数的操作可以分为几类:
Category |
Constant names |
Header |
Number of ioctls |
disk labels |
DIOxxx |
|
6 |
file I/O |
FIOxxx |
|
9 |
mag tape I/O |
MTIOxxx |
|
11 |
socket I/O |
SIOxxx |
|
60 |
terminal I/O |
TIOxxx |
|
44 |
3.16 /dev/fd/xxx
打开一个/dev/fd/n文件,如果该文件已经被打开,就类似于调用dup()。好处是,为stdio等提供了一个文件路径名的方式来定位。