免费注册 查看新帖 |

Chinaunix

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

关于SIGCHLD 信号的处理问题,求救 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-07-06 23:10 |只看该作者 |倒序浏览
写的一段代码
signal( SIGCHLD, sig_deal );

while ( 1 )
{         
        pid = fork() ;

        if ( pid == 0 )
    {
        if ( db_deal() != 0 )
                {
                        ........
                }

                exit( 0 ) ;
    }
    else if ( pid < 0 )
        {
                .......
        }

        sleep( 10 );

}

int sig_deal( int sig )
{
        pid_t pid ;
        int stat ;

        switch ( sig )
        {
                case SIGCHLD:
                        while( (pid=waitpid( 0, &stat, WNOHANG )) > 0 )
                        {
                                .......
                        }
        ......
        }

        return ( 0 );
}

其中db_deal是一个对数据的操作函数,先连接数据库,然后对数据进行处理以后提交退出;
上面这段代码很奇怪,有以下几个问题:
1、如果我在db_deal 中不对数据库进行任何操作直接返回,那样的话在主进程里面设置的
        sleep(10)就能够实现,如果在db_deal 中进行数据库操作,那么主进程就不进行等待,直接进行下一次循环;
2、但是如果我把 SIGCHLD 信号的处理改成 SIG_IGN 的时候,即使对数据库进行操作也能够实现等待;
这个问题困扰我好几天了,请高人指点

论坛徽章:
0
2 [报告]
发表于 2008-07-06 23:39 |只看该作者
对应你的问题1描述:
我想应该是这样的。
子进程不进行数据库操作,立刻退出。父进程还没有运行到sleep (10),这样,sleep (10)会得到运行。看到的现象是父进程可以sleep。我想这里,如果子进程不操作数据库,而是sleep(2),应该父进程也差不多是sleep(2)就会进入下一次循环。(因为父进程的sleep(10)在2秒时候被SIGCHLD中断了。

和上面的分析一样,当你设定了SIGCHLD为忽略时候,sleep (10)的执行就不会被中断。
因此,可以看到父进程确实执行了等待。


不知道你明白没有?

论坛徽章:
0
3 [报告]
发表于 2008-07-07 09:53 |只看该作者
to :  LZ

父进程的判断条件是pid>0

pid<0属于错误

pid==0是子进程


你给出的示例代码,并没有看出有 父进程的 痕迹

PS:最近在C版看到不只一次这种示例代码,我想知道这些代码例子是从哪里看到的???

论坛徽章:
0
4 [报告]
发表于 2008-07-07 11:38 |只看该作者
原帖由 net_robber 于 2008-7-7 09:53 发表
to :  LZ

父进程的判断条件是pid>0

pid

看帖要仔细
while ( 1 )
{
    pid = fork() ;  
                           
    if ( pid == 0 )                     
    {                                                      
        if ( db_deal() != 0 )
        {
            ........
        }                  

        exit( 0 ) ;                                    
    }                                                      
    else if ( pid < 0 )
    {                              
        .......                                         
    }                                                               

    sleep( 10 );               
}

论坛徽章:
0
5 [报告]
发表于 2008-07-07 11:45 |只看该作者
原帖由 bosi_cat 于 2008-7-6 23:10 发表
写的一段代码
signal( SIGCHLD, sig_deal );

while ( 1 )
{         
        pid = fork() ;

        if ( pid == 0 )
    {
        if ( db_deal() != 0 )
                {
               ...


你应该在sleep之前先屏蔽信号, sleep以后再放开, 否则sleep往往不会如你希望般工作
   else if ( pid < 0 )
    {                              
        .......                                         
    }                                                               

    // sigprocmask()
    sleep( 10 );
    // sigsuspend()}

论坛徽章:
0
6 [报告]
发表于 2008-07-08 12:31 |只看该作者
to 2楼:
你说的有道理,我也想到了应该是SIGCHLD信号把父进程的sleep中断了,但是现在就是想不到什么办法来搞一下

to 3楼:
父进程不做什么东西,就是睡眠10秒,估计你看叉了,哈哈

to 5楼:
你说的这个办法我没想到,我一会试试,应该可以,多谢啊

论坛徽章:
0
7 [报告]
发表于 2008-07-09 20:34 |只看该作者
to 5楼:
多谢你了,按照你的办法成功解决这个问题,以前没用过这这两个函数,我看了前面几个函数就没往下看了,不过你的方法要修正一点点:
sigprocmask();
sigsuspend();
sleep( 10 );
sigprocmask();

这样就可以了,按照你的办法可以实现等待,但是会始终会有一个死进程

论坛徽章:
0
8 [报告]
发表于 2008-07-10 11:57 |只看该作者
原帖由 bosi_cat 于 2008-7-9 20:34 发表
to 5楼:
多谢你了,按照你的办法成功解决这个问题,以前没用过这这两个函数,我看了前面几个函数就没往下看了,不过你的方法要修正一点点:
sigprocmask();
sigsuspend();
sleep( 10 );
sigprocmask(); ...


兄弟, 你对sigsuspend理解的可能不大对
sigsuspend是等待一个信号, 或者说, 按照你修改的代码来讲:

  1. sigprocmask();
  2. sigsuspend();
  3. sleep( 10 );
  4. sigprocmask();
复制代码

1. sigsuspend会阻塞, 如果sigsuspend执行后始终没有信号的话, sleep( 10 )是执行不到的, 这可能就是你所说的"死进程"的原因所在

2. sigprocmask只设置一次就够了, 一般应该在循环外设置
其实按照你的需求, 代码似乎应该这么写

  1. sigprocmask();

  2. while( 1 )
  3. {   
  4.     sleep( 10 );
  5.     if( sigpending() ) // 在这里检查未决信号
  6.     {
  7.         sigsuspend(); // 确定有未决信号后, 才有的放矢
  8.     }
  9. }
复制代码

[ 本帖最后由 isnowran 于 2008-7-10 11:58 编辑 ]

论坛徽章:
0
9 [报告]
发表于 2008-07-22 22:14 |只看该作者
楼上的这种写法,sleep可能不起作用,我还没写了试过,因为sleep的时候如果收到子进程的SIGCHLD信号,sleep就被干扰了,我那样的写就是为了在sleep以前把SIGCHLD信号屏蔽掉,等父进程睡醒了再恢复过来; 另外, sigprocmask 如果只设置一次的话,好像就把SIGCHLD信号永远的屏蔽掉了吧
我再试试你的这个方法,信号编程的这些函数不是很好理解就是了

论坛徽章:
0
10 [报告]
发表于 2008-07-22 23:35 |只看该作者
我觉得不需要这么麻烦的啦。 搜索一下sleep函数的manual,返回值的解释如下:
     If the sleep() function returns because the requested time has elapsed,
     the value returned will be zero.  If the sleep() function returns due to
     the delivery of a signal, the value returned will be the unslept amount
     (the requested time minus the time actually slept) in seconds.

就是说,假如它返回大于0,你再sleep剩余时间值不就好了啊,上面代码的

sleep(10);

改为:

int sleep_time = 10;
while (sleep_time = sleep(sleep_time) >0)
{
    sleep(sleep_time);
}

就好了嘛,省的屏蔽信号,阻塞乱七八糟的麻烦。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP