免费注册 查看新帖 |

Chinaunix

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

pause、signal等系统调用发生的问题 [复制链接]

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-05-26 18:13 |只看该作者 |倒序浏览
这两天在写ftp客户端程序时,才发现以前对进程间同步的掌握太菜了,下面这个问题请各位帮忙看看,先看源代码:

28 void sig_handler(int sig)
29 {
30     sigusr=1;
31     return;
32 }
33
34 int main()
35 {
36     pid_t pid;
37
38     (void)signal(SIGUSR1, sig_handler);
39     pid=fork();
40
41     switch(pid){
42     case -1:
43         perror("fork error!");
44         exit(1);
45     case 0:
46         while(1){
47             printf("child is going to send a signal.\n");
48             kill(getppid(), SIGUSR1);
49             printf("child begins to sleep...\n");
50             sleep(2);
51         }
52         break;
53     default:
            printf("parent begins to pause...\n");
            pause();
62     }
63
64     return 0;
65 }
----------------------
我为了验证同步问题,写了这个测试程序,结果发现父进程并不能总是被kill来的消息唤醒,如下面的输出信息所示:

[admin@localhost signal]$ ./synsignal
child is going to send a signal.
child begins to sleep...
signal is handled
parent begins to pause...
child is going to send a signal.
child begins to sleep...
用户定义信号 1  =====> 父进程已经退出了

偶尔会有如下正常预期结果出现
------------------------------
[admin@localhost signal]$ ./synsignal
child is going to send a signal.
parent begins to pause...
child begins to sleep...
signal is handled
parent wakes up now
-------------------------------------

为啥pause不能被kill正常唤醒?

论坛徽章:
0
2 [报告]
发表于 2009-05-27 00:57 |只看该作者
pause暂停父进程后,等待信号

子进程向父进程发送SIGUSR1信号,由于父进程捕获了这个信号,所以信号处理器得到执行

然后父进程会从pause函数调用处返回,接着自然就是退出了,后面父进程也没代码了。

楼主看一下pause函数的说明,它挂起进程,直接进程接收到已捕获的信号,或者导致进程终止的信号


另外,就楼主的这个程序,父进程实际上可能会接收到多次子进程的信号
因为父进程一开始就设置了信号处理器,在父进程还没有执行到pause的时候,子进程就有可能已经发送信号给父进程了

父进程调用了pause之后,就只能再收一次信号就直接退出了

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
3 [报告]
发表于 2009-05-27 14:01 |只看该作者

回复 #2 雨过白鹭洲 的帖子

不好意思,该问题我粗心将代码贴错了,再请kevin帮忙指出问题,上述问题代码中父进程也是一个死循环,不是pause一次就结束了,如下所示

53     default:
54         for(;{
55             printf("parent begins to pause...\n";
56             pause();
57
58         }

而输出就是如下内容:
[admin@localhost signal]$ ./synsignal
child is going to send a signal.
parent begins to pause...
parent begins to pause...
child begins to sleep...
child is going to send a signal.
child begins to sleep...
用户定义信号 1

仍然会产生父进程自己退出的问题,为啥? 按书上内容说明,当一个进程收到了没有预定义的信号时,默认结果是结束进程,但是这里明明父进程定义了改信号的处理程序,并且始终在循环中间呀,怎么会突然自己就被导致结束了呢?

[ 本帖最后由 jiufei19 于 2009-5-27 14:07 编辑 ]

论坛徽章:
0
4 [报告]
发表于 2009-05-27 14:20 |只看该作者
楼主一定出现幻觉了

进程退出,我推测,你用的系统可能每次信号触发后,需要重新注册信号,不然父进程第二次收到USER1,默认是退出的。

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
5 [报告]
发表于 2009-05-27 15:52 |只看该作者

回复 #4 anthony1983 的帖子

我用的是fedora 8,难道anthony1983的意思是信号处理程序每用一次就要重新注册一次才能处理下一个同样的信号吗?
我的确昏头了,我没有太明白“幻觉”的含义

虽然信号用于进程同步的确不多见,不过我想真正搞清楚其用途,谢谢大家支持

论坛徽章:
0
6 [报告]
发表于 2009-05-27 16:00 |只看该作者
原帖由 jiufei19 于 2009-5-27 15:52 发表
我用的是fedora 8,难道anthony1983的意思是信号处理程序每用一次就要重新注册一次才能处理下一个同样的信号吗?
我的确昏头了,我没有太明白“幻觉”的含义

虽然信号用于进程同步的确不多见,不过我想真 ...


有的系统是需要重新注册的。编程习惯也是重新注册一次--跨平台

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
7 [报告]
发表于 2009-05-27 16:35 |只看该作者

回复 #5 jiufei19 的帖子

谢谢anthony1983的帮助,果然我在父进程的死循环中加上重新注册新号处理函数后,就能再次接受SIGUSR1信号并处理而不退出了,如下代码所示。不过我非常奇怪,难道信号处理都是这样一个怪异模式?即都必须在一次处理完毕后再次注册

-----------------------------
52     default:
53         while(1){
54             printf("parent begins to pause...\n");
55             pause();
                  
56             signal(SIGUSR1, sig_handler);   ========> 重新注册!
57
58             printf("parent wakes up now\n");
59         }

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
8 [报告]
发表于 2009-05-27 16:41 |只看该作者
原帖由 jiufei19 于 2009-5-27 16:35 发表
谢谢anthony1983的帮助,果然我在父进程的死循环中加上重新注册新号处理函数后,就能再次接受SIGUSR1信号并处理而不退出了,如下代码所示。不过我非常奇怪,难道信号处理都是这样一个怪异模式?即都必须在一次处 ...



不好意思,搞科学不能草率,我收回刚才的结论,刚才尽管重新注册,最终结果还是不正确,刚才说正确只是巧合罢了,我再次执行程序,则父进程又退出了,看来还是有问题

论坛徽章:
0
9 [报告]
发表于 2009-05-27 16:52 |只看该作者

回复 #8 jiufei19 的帖子

这个代码会有问题????
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

void sig_handler(int sig)
{
        (void)signal(SIGUSR1, sig_handler);
        printf("parent recv [%d]...\n",sig);
}

int main()
{
     pid_t pid;

     (void)signal(SIGUSR1, sig_handler);
     pid=fork();

     switch(pid){
     case -1:
         perror("fork error!");
         exit(1);
     case 0:
         while(1){
            printf("child is going to send a signal.\n");
             kill(getppid(), SIGUSR1);
             printf("child begins to sleep...\n");
             sleep(2);
         }
         break;
     default:
           for (;;)
        {                              
            printf("parent begins to pause...\n");
            pause();
                printf("parent wake up...\n");
        }
     }

     return 0;
}


a.out
parent begins to pause...
child is going to send a signal.
child begins to sleep...
parent recv [30]...
parent wake up...
parent begins to pause...
child is going to send a signal.
child begins to sleep...
parent recv [30]...
parent wake up...
parent begins to pause...
child is going to send a signal.
child begins to sleep...
parent recv [30]...
parent wake up...
parent begins to pause...
child is going to send a signal.
child begins to sleep...
parent recv [30]...
parent wake up...
parent begins to pause...
child is going to send a signal.
child begins to sleep...
parent recv [30]...
parent wake up...
parent begins to pause...

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
10 [报告]
发表于 2009-05-27 17:10 |只看该作者

回复 #9 anthony1983 的帖子

是的,就是这个代码在我的机器上就会出现父进程退出的问题,并且刚才我加上重新注册信号处理程序后,第1次运行时,显示的结果和你贴出来的一样,我当时以为对了,结果多运行几遍,就又开始退出了。

顺便问下,在你的机器上多次重复运行都能得到此正确结果吗?

[ 本帖最后由 jiufei19 于 2009-5-27 17:11 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP