免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4067 | 回复: 11
打印 上一主题 下一主题

[C] fcntl加文件锁什么时候会被信号中断? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-07 19:38 |只看该作者 |倒序浏览
10可用积分
[本问题已解决]
经过timespace的提醒,使用sigaction替代signal来注册SIGARLM,使得fcntl被信号中断以后得以重启(SA_RESTART),代码如下
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
extern int errno;
extern "C" void s(int sig,siginfo_t *, void *){
printf("signal handle: %d\n",sig);
}
int main(void){
int fdes=open("kg",O_RDWR|O_CREAT,0664);
if(fdes<0){
  printf("open fail\n");
  exit(1);
}
struct sigaction act,oact;
sigemptyset(&act.sa_mask);
act.sa_sigaction=s;
act.sa_flags=SA_RESTART;
sigaction(SIGALRM,&act,&oact);
struct flock lock;
lock.l_type=F_WRLCK;
lock.l_start=0;
lock.l_whence=SEEK_SET;
lock.l_len=0;
alarm(5);
if(fcntl(fdes,F_SETLKW,&lock)==-1){
  alarm(0);
  printf("error=%d,%s\n",errno,strerror(errno));
  close(fdes);
  exit(1);
}
printf("lock got\n");
signal(SIGALRM,SIG_IGN);
sleep(60);
close(fdes);
return 0;
}

现在两个进程能同时运行,不会出现system call interrupted了! 分送出!

-------------------------------------------------------------------------
在一台Solaris的工作站遇到一个问题
int fdes = open(path,O_RDWR|O_CREAT,0664);
if(fcntl(fdes,F_SETLKW,&lock)  == -1){
printf("%d text: %s\n",lerrno,strerror(lerrno));
}
...
...

这段程序遇到了错误,打印:
4 text: Interrupted system call
我查了一下手册:
F_SETLKW:行为如同F_SETLK,除了不能获取锁时会睡眠等待外。如果在等待的过程中接收到信号,会立即返回并将errno置为EINTR

我把问题提取出来了,形成一个小程序:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
extern int errno;
extern "C" void s(int sig){
printf("signal handle: %d\n",sig);
}
int main(void){
int fdes=open("kg",O_RDWR|O_CREAT,0664);
if(fdes<0){
  printf("open fail\n");
  exit(1);
}
signal(SIGALRM,&s);
struct flock lock;
lock.l_type=F_WRLCK;
lock.l_start=0;
lock.l_whence=SEEK_SET;
lock.l_len=0;
alarm(5);
if(fcntl(fdes,F_SETLKW,&lock)==-1){
  signal(SIGALRM,SIG_IGN);
  alarm(0);
  printf("error=%d,%s\n",errno,strerror(errno));
  close(fdes);
  exit(1);
}
printf("lock got\n");
signal(SIGALRM,SIG_IGN);
sleep(20);
close(fdes);
return 0;
}
(1)编译运行:
一个term里面./a.out (称为进程a)
另一个term里面也瞬间./a.out (称为进程b)

(2)运行结果:
a进程运行以后对文件加锁,打印"lock got",然后睡20s,结束
b进程启动以后fcntl会等待(因为F_SETLKW),然后第5s的时候,进程接受到了SIGALRM,(因为alarm(5)的原因,然后打印
signal handle: 14
error=4,Interrupted system call

(3)问题是:
a进程为什么没有执行信号处理函数s从而打印出"signal handle: 14"
b进程的信号处理函数已经起了作用,为什么fcntl(fdes,F_SETLKW,&lock)仍然被信号中断?

测试环境: solaris8+CC
谢谢!!!!!
请问: fcntl加文件锁,什么时候会接收到信号呢? 每次运行到这里都失败。

谢谢!!!!!!

[ 本帖最后由 jeanlove 于 2009-4-8 17:11 编辑 ]

最佳答案

查看完整内容

signal(SIGALRM,SIG_IGN);sleep(20);你在sleep之前都忽略了SIGALRM,所以a不会执行s信号处理函数生效,系统调用也能被信号中断,至于系统调用是否会重启,取决于实现,也就是说看文档。只要满足各种信号的条件,就会产生,和fcntl加文件锁没什么直接联系

论坛徽章:
11
技术图书徽章
日期:2014-03-01 14:44:34天蝎座
日期:2014-05-21 22:11:59金牛座
日期:2014-05-30 17:06:14
2 [报告]
发表于 2009-04-07 19:38 |只看该作者
a进程为什么没有执行信号处理函数s从而打印出"signal handle: 14"

signal(SIGALRM,SIG_IGN);
sleep(20);
你在sleep之前都忽略了SIGALRM,所以a不会执行s

b进程的信号处理函数已经起了作用,为什么fcntl(fdes,F_SETLKW,&lock)仍然被信号中断?

信号处理函数生效,系统调用也能被信号中断,至于系统调用是否会重启,取决于实现,也就是说看文档。

请问: fcntl加文件锁,什么时候会接收到信号呢? 每次运行到这里都失败。

只要满足各种信号的条件,就会产生,和fcntl加文件锁没什么直接联系

论坛徽章:
0
3 [报告]
发表于 2009-04-07 19:41 |只看该作者

回复 #1 jeanlove 的帖子

其他参数我没有看到,但是如果你这个是一个获取锁的操作,而锁拿不到的话,就睡眠了,然后在睡眠的时候被你的信号打断了

你可以查一下你的程序里面哪儿有很频繁的发信号操作

论坛徽章:
0
4 [报告]
发表于 2009-04-08 09:05 |只看该作者
信号不一定是你自己的函数发的,或许是你调用的库,或许其他情况,但是看起来一定是你自己的程序发的。
调试器看一下

论坛徽章:
0
5 [报告]
发表于 2009-04-08 13:27 |只看该作者
原帖由 r2r4 于 2009-4-8 09:05 发表
信号不一定是你自己的函数发的,或许是你调用的库,或许其他情况,但是看起来一定是你自己的程序发的。
调试器看一下


请指教一下
是用gdb看吗
还是还有别的工具可以看

用gdb的话,怎么监控信号 最好?谢谢了

论坛徽章:
0
6 [报告]
发表于 2009-04-08 13:52 |只看该作者
原帖由 astezheng 于 2009-4-7 19:41 发表
其他参数我没有看到,但是如果你这个是一个获取锁的操作,而锁拿不到的话,就睡眠了,然后在睡眠的时候被你的信号打断了

你可以查一下你的程序里面哪儿有很频繁的发信号操作


有了一点进展,我把问题提取出来了,形成一个小程序,1楼的帖子贴出来了。

[ 本帖最后由 jeanlove 于 2009-4-8 14:24 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2009-04-08 14:35 |只看该作者
刚看过了,也在我的机器上跑了,那个alarm5,没有打断那个求锁的wait

后启动的进程没有进入到错误处理
if(fcntl(fdes,F_SETLKW,&lock)==-1){
  signal(SIGALRM,SIG_IGN);
  alarm(0);
  printf("error=%d,%s\n",errno,strerror(errno));
  close(fdes);
  exit(1);
}

这可能和sianal那个函数的实现有关,可能对被中断的系统调用加了restart处理,这样吧,如果你还有什么线索,可以帖一下,下午我研究下,晚上给你帖

论坛徽章:
0
8 [报告]
发表于 2009-04-08 14:46 |只看该作者

回复 #6 astezheng 的帖子

太奇怪了
碰上alarm信号,fcntl重启了

       F_SETLKW
              As  for F_SETLK, but if a conflicting lock is held on the file, then wait for that lock to be released.  If a sig‐
              nal is caught while waiting, then the call is interrupted and (after the  signal  handler  has  returned)  returns
              immediately (with return value -1 and errno set to EINTR).

按说一般的对系统调用有重启处理的信号里面是不会包括SIG_ALARM的,晚上吧,不好意思,现在得干活了

论坛徽章:
0
9 [报告]
发表于 2009-04-08 15:20 |只看该作者
原帖由 timespace 于 2009-4-8 14:59 发表

signal(SIGALRM,SIG_IGN);
sleep(20);
你在sleep之前都忽略了SIGALRM,所以a不会执行s


信号处理函数生效,系统调用也能被信号中断,至于系统调用是否会重启,取决于实现,也就是说看文档。


只要满 ...

补充一点:

我把原程序中的alarm()和signal(SIGALRM)去掉了,换成了signal(SIGHUP),然后我在a,b两个进程运行的时候:
>kill -HUP <b的pid>

同样,b进程打印
signal handle: 14
error=4,Interrupted system call

并退出。也就是说在solaris8这个环境上面,fcntl会被所有的signal中断。
为什么呢?

论坛徽章:
11
技术图书徽章
日期:2014-03-01 14:44:34天蝎座
日期:2014-05-21 22:11:59金牛座
日期:2014-05-30 17:06:14
10 [报告]
发表于 2009-04-08 15:42 |只看该作者
原帖由 jeanlove 于 2009-4-8 15:20 发表

我把原程序中的alarm()和signal(SIGALRM)去掉了,换成了signal(SIGHUP),然后我在a,b两个进程运行的时候:
>kill -HUP <b的pid>

同样,b进程打印
signal handle: 14
error=4,Interrupted system call

并退出。也就是说在solaris8这个环境上面,fcntl会被所有的signal中断。
为什么呢?


首先,信号的作用就是用来中断程序的正常流程,以作特殊处理。所以除了忽略的或默认行为是忽略的信号,都可以中断阻塞的fcntl,比如你这里的SIGHUP,SIGINT,SIGALRM等等,至于“为什么“,信号本来就是干这事儿的。

其次,POSIX.1允许重启被中断的系统调用,但是这不是必需的,如FreeBSD, Linux默认重启被中断的系统调用,而Solaris就是出错返回,设置errno为EINTR。而且sigaction可以控制系统调用是否需要重启,所以这些实现都是合理的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP