阻塞非阻塞
产生阻塞的场景,读设备文件,读网络文件(读常规文件不需要阻塞)
/dev/tty–终端文件
阻塞非阻塞是设备文件,网络文件的属性,O_NONBLOCK
fcntl()函数
头文件
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
定义
int fcntl(int filedes, int cmd,.../* int arg * / ) ;
//第三个参数可以是long,int, 结构体指针
返回值
成功:依赖于cmd
出错:- 1
参数
- cmd
- 复制现存的文件描述符
cmd = F_DUPFD
//复制文件描述符,fd和 newfd不相等,但是指向同一个文件表(包含文件状态标志,当前文件位移量,v节点指针)
fd = open("a.txt", O_RDWR);
newfd = fcntl(fd, F_DUPFD, 1);
close(fd)//文件并没有关闭,还有newfd
- 获得/设置文件状态标志
获得:cmd = F_GETFL
flag = fcntl(fd, F_GETFL);
示例:
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
// 0000 O_RDNOLY
// 0001 O_WRONLY
// 0010 O_RDWR
// 0011 O_ACCMODE
// 1000 O_NONBLOCK
int fd = open("a.txt", O_RDONLY | O_APPEND | O_NONBLOCK);
int flag = fcntl(fd ,F_GETFL);
//O_ACCMODE = 0011, 取flag的后两位
if ((flag & O_ACCMODE) == O_RDONLY)
{
printf("O_RDONLY\n");
}
else if ((flag & O_ACCMODE) == O_WRONLY)
{
printf("O_WRONLY\n");
}
else if ((flag & O_ACCMODE) == O_RDWR)
{
printf("O_RDWR\n");
}
if (flag & O_APPEND)
{
printf("O_APPEND\n");
}
if (flag & O_NONBLOCK)
{
printf("O_NONBLOCK\n");
}
close(fd);
return 0;
}
//设置文件标志阻塞为非阻塞
int flag = fcntl(STDIN_FILENO, F_GETFL);
flag = flag | NONBLOCK;
fcntl(STDIN_FILENO, F_SETFL, flag);
- 获得/设置记录锁
- cmd = F_GETLK
- cmd = F_SETLK//尝试上锁,不阻塞,如果其它进程已经锁住了,无法上锁时,直接返回失败
如果没有被锁住的话,直接返回上锁成功 - cmd = F_SETLKW//会阻塞,如果其它进程已经锁住了,无法上锁时,fcntl函数会等待其它进程释放锁为止才返回
- fcntl的第三个参数此时是指向结构体flock的指针
记录锁
- 记录锁(record locking)的功能是:一个进程正在读或修改文件的某个部分时,可以阻止其他进程修改同一文件区。
- 多个进程操作同一个文件要上读写锁
- struct flock结构体的定义如下:
struct flock {
short l_type; /* 记录锁类型,F_RDLCK(共享读锁),F_WRLCK(独占性锁)或F_UNLCK(解锁一个区域) */
off_t l_start; /* 起始位置偏移量,单位字节,是相对于l_whence而言 */
short l_whence; /* SEEK_SET,SEEK_CUR,或SEEK_END */
off_t l_len; /* 长度,单位字节,值为0时表示一直到文件尾 */
pid_t l_pid; /* 使用F_GETLK时返回此值 */
}
文件加锁状态 | 是否能上读锁 | 是否能加写锁 |
---|---|---|
无锁 | 是 | 是 |
读锁 | 是 | 否 |
写锁 | 否 | 否 |
文件上锁
int fd = open("a.txt", O_RDONLY);
struct flock fl;
//上读锁
fl.l_type = F_RDLCK;
fl.l_start = 0;
fl.l_whence = SEEK_SET;
fl.len = 0;
fcntl(fd, F_SETLKW, &fl);
//解锁
fl.l_type = F_UNLCK;
fcntl(fd, F_SETLK, &fl);
死锁
- 如果两个进程相互等待对方持有并且不释放(锁定)的资源时,则这两个进程就处于死锁状态。
- 如果一个进程已经控制了文件中的一个加锁区域,然后它又试图对另一个进程控制的区域加锁,则它就会睡眠,在这种情况下,有发生死锁的可能性。