Chinaunix首页 | 论坛 | 博客
  • 博客访问: 84442
  • 博文数量: 9
  • 博客积分: 129
  • 博客等级: 民兵
  • 技术积分: 155
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-22 00:01
个人简介

今天决定明天

文章分类
文章存档

2013年(4)

2012年(5)

分类: C/C++

2013-01-22 11:16:05

小编在这片文章中就不说 fcntl 如何使用了,如果有不明白的地方,请转到去问度娘:“ Linux fcntl”, 她会告诉我们一大堆。
在这里我把我今天用这个函数遇到的一些问题列举下,如有写的不对的地方,还望各位高手指正,不甚感激!
include 
#include 
#include 

int main()
{
int fd;
int ret;
struct flock rflk, wflk;

fd = open("txt", O_RDONLY);
if(fd < 0) {
perror("open failed");
return 1;
}

ret = fcntl(fd, F_GETFD); 
printf("current descriptor flags: %d\n", ret);
fcntl(fd, F_SETFD, 1);
printf("current descriptor flags: %d\n", ret);

rflk.l_type = F_RDLCK;
rflk.l_whence = SEEK_SET;
rflk.l_start = 0;
rflk.l_len = 10;
wflk = rflk;
wflk.l_type = F_WRLCK;

if(fcntl(fd, F_SETLK, &rflk) == -1) {
perror("read lock failed");
return 1;
}
if(fcntl(fd, F_SETLK, &wflk) == -1) {
perror("write lock failed");
return 1;
}

close(fd);
return 0;
}

上面这段程序执行结果:
current descriptor flags: 0
current descriptor flags: 0
write lock failed: Bad file descriptor
错误的文件描述符,一时半会不知道什么原因,后面检查程序
这里 fd = open("txt", O_RDONLY); 打开文件只是以制度方式打开的,而我要去加一把写锁,当然出错了,于是改为 fd = open("txt", O_RDWR); 好了,把读锁和写锁都加上去了。
是不是没问题了,不然,在网上看到有人说读写锁只能同时存在一个,那这里为什么读写锁都加上去了呢? 好好想想,会不会是在同一个进程中既可以加读锁也可以加写锁,因为该文件资源都属于该进程,改进程想读就读,想写就写! 于是,咋们就来创建一个子进程。把上面的代码改了
#include 
#include 
#include 

int main()
{
int fd;
int ret;
struct flock rflk, wflk;

fd = open("txt", O_RDWR);
if(fd < 0) {
perror("open failed");
return 1;
}

ret = fcntl(fd, F_GETFD); 
printf("current descriptor flags: %d\n", ret);
fcntl(fd, F_SETFD, 1);
printf("current descriptor flags: %d\n", ret);

rflk.l_type = F_RDLCK;
rflk.l_whence = SEEK_SET;
rflk.l_start = 0;
rflk.l_len = 10;
wflk = rflk;
wflk.l_type = F_WRLCK;

if(fcntl(fd, F_SETLK, &rflk) == -1) {
perror("read lock failed");
return 1;
}
if(fcntl(fd, F_SETLK, &wflk) == -1) {
perror("write lock failed");
return 1;
}
if(fork()) {
if(fcntl(fd, F_SETLK, &rflk) == -1) {
fprintf(stderr, "parent read lock failed\n"); 
}
if(fcntl(fd, F_SETLK, &wflk) == -1) {
fprintf(stderr, "parent write lock failed\n"); 
}
sleep(3);
} else {
sleep(1); 
if(fcntl(fd, F_SETLK, &rflk) == -1) {
fprintf(stderr, "child read lock failed\n"); 
}
if(fcntl(fd, F_SETLK, &wflk) == -1) {
fprintf(stderr, "child write lock failed\n"); 
}
}

close(fd);
return 0;
}
编译执行结果为:
current descriptor flags: 0
current descriptor flags: 0
child read lock failed
child write lock failed
果然,在子进程中,不能再次加锁了。
在想,读锁不是可以存在多个吗?怎么子进程中的读锁也失败了,会不会是因为父进程中有写锁,导致子进程加读写锁都失败了,把父子进程中的加写锁注释掉
再次编译,运行:
current descriptor flags: 0
current descriptor flags: 0
说明问题还真是因为父进程中有写锁。
那么如果父进程中有读锁,在子进程中加写锁是否成功呢?下面取消注释掉子进程中的加写锁:
current descriptor flags: 0
current descriptor flags: 0
child write lock failed
可见,即便父进程中没有写锁,子进程中也不能加写锁,因为父进程已经存在了读锁!


好了,先到此为止,做个总结
fcntl函数来加锁文件,网上有人说读写锁只能同时存在一个,这是不全面的,进过上面的测试代码可知。

1、在同一进程可以加多次读锁,多次写锁,并且可以同时存在!

上次这里说错了,在同一进程中,锁也并不是同时存在的,而是后面加的锁会覆盖前面加的锁!(2013/1/24修改)

2、在不同进程中,如果进程A拥有读锁或写锁, 那么进程B只能有读锁,不能加写锁

3、还需要注意的是,在上面加锁的时候我们把 fcntl 的第二个参数cmd 都置为 F_SETLK,如果把它换成 F_SETLKW,那么在不同进程间可同时加读写锁。假设进程A先拥有了某个锁,进程B想给自己加一把锁,那么就会等到进程A把锁释放掉!

4、如果调用 fcntl(fd, F_GETLK, &flk) 时,如果能够得到这样的锁,那么设置 flk.l_type == F_UNLCK, flk 其他成员值不变; 否则,如果不能得到这样的锁,重新设置 flk 的值,使 l_pid == 当前占用锁的进程。


阅读(12423) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~