第十四章:高级I/O

一、非阻塞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

本节在第七章:进程环境六、存储空间分配有详细陈述。

猜你喜欢

转载自www.cnblogs.com/Lioker/p/10943807.html