一、非阻塞I/O
对于一个给定的描述符,有两种为其指定非阻塞I/O的方法。
1. 如果调用open()函数获得描述符,可以使用O_NONBLOCK标志。如int fd = open("a.txt", O_RDWR | O_NONEBLOCK);
2. 对于已经打开的描述符,可以使用fcntl()函数设置O_NONBLOCK标志。
二、文件锁
在此使用之前的例子:假设进程或线程A对一个文件写入3000个字符“a”,而另一个进程或线程B对这个文件写入3000个“b”,第三个进程或线程C读取这个文件,会导致读取数据不一定是什么。
文件锁解决的是多进程或多线程同时操作文件产生数据冲突的问题。同一进程内部使用文件锁没有效果。
设置文件锁使用fcntl()函数。所使用的文件锁结构体为struct flock,其定义如下:
struct flock{ short l_type; // 锁的类型,包括读锁、写锁和释放锁,分别对应F_RDLCK、F_WRLCK、F_UNLCK short l_whence; // 锁定起始点的参考位置,SEEK_SET、SEEK_END、SEEK_CUR off_t l_start; // 锁定起始点的偏移量 off_t l_len; // 锁定区域的大小,锁定的长度 pid_t l_pid; // 锁定进程的PID,只有GETLK用得到,给-1即可 }
示意图如下:
文件锁允许多个进程同时读,但不允许同时写。因此文件锁分为读锁和写锁。读锁针对读操作,允许其他进程读文件,但不允许写;写锁针对写操作,是不允许其他进程读和写。
文件锁一般用于多进程或多线程代码中。
通过fcntl()的参数解释,可知锁定的方式有阻塞等待锁定和立即锁定(F_SETLK)。阻塞等待锁定如果锁不上就会一直阻塞等待,直到其它进程释放锁后继续上锁。立即锁定如果锁不上就会立即返回-1。
文件锁示例代码如下:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <fcntl.h> 5 6 int main() 7 { 8 int fd = open("a.txt", O_RDWR | O_CREAT, 0666); 9 10 struct flock lock; 11 lock.l_type = F_WRLCK; 12 lock.l_whence = SEEK_SET; 13 lock.l_len = 10; 14 lock.l_start = 0; 15 lock.l_pid = -1; 16 17 int err = fcntl(fd, F_SETLK, &lock); 18 if (err == -1) 19 printf("上锁失败\n"); 20 else { 21 printf("上锁成功\n"); 22 write(fd, "Hello World", 11); 23 lock.l_type = F_UNLCK; 24 fcntl(fd, F_SETLK, &lock); 25 } 26 27 close(fd); 28 }
三、select()和poll()
对于两函数,读者可查看四、poll()、select()和epoll()中第一节到第四节。
四、存储映射I/O
本节在第七章:进程环境的六、存储空间分配有详细陈述。
下一章 第十五章:进程间通信