天天看点

LinuxC:信号处理 alarm() 信号集操作函数 sigprocmask() sigpending() sigsuspend() SIGCHILD信号 实现sleep()

LinuxC:信号处理 alarm() 信号集操作函数 sigprocmask() sigpending() sigsuspend() SIGCHILD信号 实现sleep()
  • kill -l:Linux查看当前系统有哪些信号

    man 7 signal:Linux查看信号手册

    ulimit -a:Linux命令可查看core文件大小(core file size)

    ulimit -c 1024:Linux命令设置core文件大小为1024

    ulimit -c unlimited: 大小设置为无限制

  • Tern:终止当前进程

    Core:Tern并且Core Dump(产生core文件)

    Ign:忽略信号

    Stop:停止(暂停)当前进程

    Cont:继续执行之前Stop的进程

    SIGINT信号:例如键盘按下Ctrl+C

    信号递达delivery:实际执行信号的处理动作

    信号未决pending:信号产生到递达之间的状态,例如进程阻塞时的状态

  • kill命令是调用**kill()**函数实现的。成功返回-,失败返回-1
  • alarm() 告诉内核几秒后给当前进程发送SIGALRM信号
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
           
  • 信号集操作函数
#include <signal.h>

//以下4个函数 成功返回0,失败返回-1
int sigemptyset(sigset_t *set); //清空信号集
int sigfillset(sigset_t *set); //初始化信号集
int sigaddset(sigset_t *set, int signo); //添加sign o信号
int sigdelset(sigset_t *set, int signo); //删除signo信号

//返回1表示有此信号 返回0表示没有此信号 返回-1表示出错
int sigismember(const sigset_t *set, int signo); 
           
  • 信号屏蔽字:当前进程的阻塞信号集
#include <signal.h>

//读取或更改进程的信号屏蔽字
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
           
  • 未决信号集 成功返回1,出错返回-1
#include <signal.h>

//读取当前进程的未决信号集
int sigpending(sigset_t *set);
           
  • 捕捉信号:信号的处理动作是用户自定义函数,信号递达时即调用此函数,例如sigaction() 更改信号
  • pause() sigsuspend():调用进程挂起直到有信号递达 返回值只有-1

    只有执行捕捉信号的函数才返回-1,其余没有机会返回,errno=EINTR

#include <unistd.h>
int pause();

#include <signal.h>
//除了有pause()的功能,还解决了竞态条件,时序要求严格要用这个函数
int sigsuspend(const sigset_t *sigmask);
           
  • 实现sleep()
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>

void sig_alarm(int signo) {
    return ;
}

unsigned int mysleep(unsigned int sec) {
    struct sigaction newact, oldact;
    sigset_t newmask, oldmask, susmask; //信号屏蔽字

    newact.sa_handler = sig_alarm;
    newact.sa_flags = 0;
    sigemptyset(&newact.sa_mask);

    sigaction(SIGALRM, &newact, &oldact);

    //阻塞闹钟信号
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGALRM);
    sigprocmask(SIG_BLOCK, &newmask, &oldmask);

    alarm(sec); //启动闹钟

    susmask = oldmask;
    //删除alarm信号
    sigdelset(&susmask, SIGALRM);
    //挂起程序等信号到来 临时设置susmask信号屏蔽字
    sigsuspend(&susmask);

    int unslept = alarm(0);
    sigaction(SIGALRM, &oldact, NULL);
    sigprocmask(SIG_SETMASK, &oldmask, NULL); //读取或更改进程的信号屏蔽字

    return unslept;
}

int main() {
    return 0;
}
           

SIGCHILD信号

  • 子进程退出时会发此信号,此信号可自定义信号处理函数sigaction()
  • Linux下直接处理不产生僵尸进程的信号方法:

    父进程调用sigaction()将SIGCHILD信号的处理动作置为SIG_IGN。

    此时fork()出来的子进程在终止时会自动清理掉,不产生僵尸进程,也不会通知父进程。