非阻塞io与记录锁

非阻塞io

1.对比

阻塞io的例子:scanf从终端获取输入时,如果不输入程序就会一直停在那; 对一个已经有写锁的文件请求读时, 会一直空等直到前面的进程释放锁...

非阻塞的例子:读取文件内容, 如果文件当前因加锁无法访问则立即出错返回

2.非阻塞io设置方法

a.调用open函数时, 指定O_NONBLOCK标志

open(filename,O_RDWR,O_NONBLOCK)

b.已经打开的fd, 调用fcntl将fd的O_NONBLOCK标志打开

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h> char buf[500000]; void set_fl(int fd,int flags){
int val;
if((val=fcntl(fd,F_GETFL,0))<0){
perror("fcntl F_GETFL error");
exit(1);
}
val|=flags;
if(fcntl(fd,F_SETFL,val)<0){
perror("fcntl F_SETFL error");
exit(1);
}
} void clr_fl(int fd,int flags){
int val;
if((val=fcntl(fd,F_GETFL,0))<0){
perror("fcntl F_GETFL error");
exit(1);
}
val &= ~flags;
if(fcntl(fd,F_SETFL,val)<0){
perror("fcntl F_SETFL error");
exit(1);
}
} int main(){
int ntowrite,nwrite;
char *ptr; ntowrite=read(STDIN_FILENO,buf,sizeof(buf));
fprintf(stderr,"read %d bytes\n",ntowrite); set_fl(STDOUT_FILENO,O_NONBLOCK); ptr=buf;
while(ntowrite>0){
errno=0;
nwrite=write(STDOUT_FILENO,ptr,ntowrite);
fprintf(stderr,"nwrite=%d,errno=%d\n",nwrite,errno); if(nwrite>0){
ptr += nwrite;
ntowrite -= nwrite;
}
} clr_fl(STDOUT_FILENO,O_NONBLOCK);
return 0;
}

执行 ./a.out < /etc/services 2>stderr.out

查看stderr.out文件会发现write函数出现了很多次相同错误,

在centos上, 出错的errno=11, Resource temporarily unavailable

书本上测试的为errno=35, Resource deadlock avoided

从结果上看, 在写入stdout时, 由于终端缓冲的原因没办法一次write完成, 所以分成很多次去写

因为设置了O_NONBLOCK, 所以提交write任务后, 如果当前终端还在处理上一个循环的write, 则本次write立即返回并设置errno

记录锁(文件锁).

1.记录锁用于多进程对文件编辑的保护

2.锁函数

int fcntl(int fd, int cmd, struct flock *lock);

cmd = F_GETLK,测试能否建立一把锁
cmd = F_SETLK,设置锁
cmd = F_SETLKW, 阻塞设置一把锁 struct flock {
short l_type; /* 锁的类型: F_RDLCK, F_WRLCK, F_UNLCK */
short l_whence; /* 加锁的起始位置:SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* 加锁的起始偏移,相对于l_whence */
off_t l_len; /* 上锁的字节数*/
pid_t l_pid; /* 已经占用锁的PID(只对F_GETLK 命令有效) */
/*...*/
};

3.锁的继承和释放

a.进程结束后, 进程所建立的锁全部释放

b.fork产生的子进程不继承父进程的锁

c.执行exec后, 新程序可以继承原执行程序的锁

4.建议锁和强制锁

建议锁:只关注fcntl加锁函数, open/read/write可以无视文件是否加锁

强制锁:read/write/open函数执行时都要检查文件是否加锁

值得注意的是, 强制锁的实现依赖系统

下面的程序运行二个实例, 第二个实例会在lockfile那一步报错

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h> int lockfile(int fd){
struct flock fl;
fl.l_type=F_WRLCK;
fl.l_start=0;
fl.l_whence=SEEK_SET;
fl.l_len=0;
return(fcntl(fd,F_SETLK,&fl));
}
#define FILE_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH
int main(){
int fd;
char *filename="./test.txt";
struct stat statbuf;
if((fd=open(filename,O_RDWR|O_CREAT,FILE_MODE))<0){
perror("open error");
exit(1);
}
if(write(fd,"abcdef",6) != 6){
perror("write error");
exit(1);
}
/*
* if(fstat(fd,&statbuf)<0){
* perror("fstat error");
* exit(1);
* }
*
* if(fchmod(fd,(statbuf.st_mode & ~S_IXGRP) | S_ISGID) <0){
* perror("fchmod error");
* exit(1);
* }
*/
if(lockfile(fd)<0){
perror("lockfile error");
exit(1);
}
while(1){
;
}
}
上一篇:Android Content Provider Guides


下一篇:WPF 访问外部的xaml文件