Linux——竟态条件和SIGCHLD

可重入函数

一个函数被多个执行流调用,有可能在第一次调用还没返回时就再次进入函数,称为重入。
这里写图片描述

例如上面的insert函数,在执行第一步时收到信号产生硬件中断,转去信号处理函数,而信号处理函恰好调用了insert函数,由于两个函数操纵了同一个链表而产生意外的结果,所以这个函数是不可重入函数。如果这个函数只是操纵自己的局部变量就是可重入的。

另外调用IO库,或者使用malloc的函数也是不可重入的。

再看volatile

学c语言的时候知道volatile可以禁止编译器优化,始终从内存里拿变量的数据,在信号里它又有什么作用?

int flag = 0;
void handler()
{
    flag = 1;
}

int main()
{
    signal(SIGALRM, handler);
    alarm(3);
    while(1){
        if(flag){
            break;
        }
        printf(".\n");
        sleep(1);
    }
}

按理说睡三秒后,应该停止打点。但是如果加入优化,编译器在main控制流里看不到flag的改变,可能会从寄存器里拿flag,而捕捉信号后即使改变了flag,系统也不知道。

如果用volatile修饰flag,就能消除这种影响。

竟态条件

上一篇博文写了一个sleep的实现,但是有隐患,我是在单执行流环境下去写的代码,但若是放在多执行流环境呢?假如alarm刚设定了一个闹钟,还没来得及挂起进程就被中断了,等到回来时闹钟信号已经响了并且已经递达,这时再去挂起进程不就永久的睡下去了吗。

    //设定闹钟
    alarm(s);
    pause();

这其实就要求着我们以新的视角去审视代码,这样的与代码时序紧密相关的错误称为竟态条件。

如果在挂起进程之前屏蔽ALRM信号能不能解决问题呢?

    //屏蔽ALRM
    alarm(s);
    //解除屏蔽ALRM
    pause();

看样子在pause之前不会递达ALRM信号了。其实解除屏蔽这一步和pause还是有竟态条件的问题,万一在解除屏蔽后被中断了。

真正的解决办法是把解除信号屏蔽和挂起设为原子操作!即使cpu中断也不能分离他俩。

int sigsuspend(const sigset_t *sigmask)

sigsuspend就是这么一个函数

sigset_t newmask, oldmask, suspmask;
//注册ALRM信号
//屏蔽ALRM信号
alarm(s);
//解除屏蔽并挂起
suspmask = oldmask;
sigdelset(&suspmask, SIGALRM);//确保ALRM没有被屏蔽
sigsuspend(&suspmask);//递达任意信号后唤醒

SIGCHLD信号

如果父进程在子进程之前终止,那么子进程变为孤儿进程,因此父进程需要wait来回收子进程,但是wait以后父进程阻塞,不能干别的事情,有没有办法让父进程干自己的事,子进程退出时自动回收?

有,子进程在退出时会给父进程发SIGCHLD信号,利用这个信号可以让父进程捕捉处理。

void handler(int signo)
{
    pid_t id;
    //有很多子进程同时发了SIGCHLD
    while((id = waitpid(-1, NULL, WNOHANG)) > 0){
        printf("wait child success %d", id);
    }
}
int main()
{
    //父进程都注册了SIGCHLD的处理函数
    signal(SIGCHLD, handler);
    pid_t cid;
    if((cid=fork()) == 0){
        printf("child");
        sleep(3);
        exit(1);
    }
    while(1){
        printf("father");
        sleep(1);
    }
}

waitpid:

  1. 当正常返回的时候,waitpid返回收集到的子进程的进程ID;
  2. 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值