信号相关

时序竞态

unsigned int mysleep(unsigned int seconds) {
    int ret;
    struct sigaction newact, oldact;

    newact.sa_handler = sig_alrm;
    sigemptyset(&act.sa_mask);
    acr.sa_flags = 0;
    sigaction(SIGALRM,&newact,&oldact);

    alarm(seconds);
    //在这一步可能发生问题,因为失去cpu控制权,时间到了SIGALRM信号在这里触发
    //等到获取cpu,将会立刻处理掉这个信号,等执行到pause()将会陷入一直挂起
    int ret = pause();
    sigaction(SIGALRM, &oldact, NULL);//用来恢复

    return ret;
}
int sigsuspend(const sigset_t *mask); //挂起等待信号,原子操作
//调用期间,进程屏蔽字由mask指定,其功能与pause()相同
//改进版
unsigned int mysleep(unsigned int seconds) {
    struct sigaction newact, oldact;
    sigset_t newmask, oldmask, suspmask;
    unsigned int unslept;

    newact.sa_handler = sig_alrm;
    sigemptyset(&act.sa_mask);
    sigaction(SIGALRM,&newact,&oldact);

    sigemptyset(&newact);
    sigaddset(&newact.sa_mask);
    sigprocmask(SIG_BLOCK, &newmask, &oldmask);

    alarm(nsecs);

    supsmask = oldmask;
    sigdelmask(&suspmask, SIGALRM);

    sigsuspend(&suspmask);
    uslpet = alarm(0);

    sigaction(SIGALARM,&oldact,NULL);
    sigprocmask(SIG_SETMASK, &oldmask, NULL);
    return uslpet;

}

全局变量的异步I/O问题

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>

int n = 0, flag = 0;

void sys_err(char* str) {
    perror(str);
    exit(0);
}

void do_sig_child(int num) {
    printf("I am child %d\t%d\n", getpid(), n);
    n += 2;
    flag = 1;
    //sleep(1);
}
void do_sig_parent(int num) {
    printf("I am parent %d\t%d\n", getpid(), n);
    n += 2;
    flag = 1;
    //sleep(1);
}

int main(void) {
    pid_t pid;
    struct sigaction act;

    if((pid = fork()) < 0) {
        sys_err("fork");
    } else if( pid > 0) {
        n = 1;
        sleep(1);
        act.sa_handler = do_sig_parent;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGUSR2, &act, NULL);

        do_sig_parent(0);
        while(1) {
            if(flag == 1) {
                kill(pid, SIGUSR1);
                flag = 0;
            }
        }
    } else {
        n = 2;
        act.sa_handler = do_sig_child;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGUSR1,&act,NULL);

        while(1) {
            if(flag == 1) {
                kill(getppid(),SIGUSR2);
                flag=0;
            }
        }
    }

    return 0;
}
从上面的代码的执行,最终会自动停止,因为没sleep去做同步。如果sleep没有被注释的话,结果是正常的。
经过分析可以发现flag是用来进行标记程序的执行进度的。在 kill() 函数执行后,还没有对flag的值进行修改,这时可能因为kernel进行调度,对方可能会发送信号回调捕捉函数,从而修改了flag的值。

解决:
- 不要使用全局变量在多个进程间
- 加锁处理

可重入函数

程序没执行完(程序执行的过程中),又一次被执行了,称为重入。

如果函数的结果因为重入发生了变化,发生了不可预料的变化。则该函数不是可重入函数。

注意:

  • 定义可重入函数,不可出现static变量、全局变量、不能使用malloc、free。
  • 信号捕捉函数应设计为可冲入函数。
  • 信号处理程序可以调用的可重入函数可以看 man 7 signal
  • 没有包含上述列表中的函数大多为不可重入函数,因为:
    • 使用了静态数据结构
    • 调用了malloc或者free
    • 是标准I/O函数

SIGCHLD信号

产生条件:

  • 子进程终止时
  • 子进程接收到SIGSTOP信号停止时
  • 子进程处在静止态,接收到SIGCONT后唤醒时

信号传参

发送信号时
int sigqueue(pid_t pid, int sig, const union sigval value); //成功0,失败-1,设置errno
union sigval {
    int sival_int;
    void* sival_ptr;
};
//向指定进程发送指定信号时,携带数据。如,传地址,需要注意的是,不同进程有不同的虚拟地址空间。
//也就是说,将本进程的虚拟地址传给其他进程是没有用的。
捕捉信号时
int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact);
struct sigaction{
    void (*sa_handler)(int);
    void (*sa_sigaction)(int, siginfo_t *, void*);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_restorer)(void);
};
当注册信号捕捉函数,希望获得更多信息时,不用sa_handler应使用sa_sigaction.但此时sa_flag必须为SA_SIGINFO。其中siginfo_t是一个结构体,可携带各种信号相关的数据。

中断系统调用

慢速系统调用在执行过程中被信号打断,这一过程称为中断系统调用。

慢速系统调用

造成进程永久阻塞
eg:wait() waitpid() pause() read()管道、设备

其他系统调用

一调用就结束。

慢速系统调用被中断后的行为

参见pause()的行为:

  • 信号不能被屏蔽。
  • 信号的处理方式必须是捕捉。
  • 中断后返回-1,设置errno为EINTR。
  • sa_flags设置被信号中断后的系统调用是否重启:
    • SA_INTERRURT不重启
    • SA_RESTART重启
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值