linux signal函数_Linux笔记(15)| Linux的信号

本文深入探讨了Linux中的信号机制,包括使用kill、raise、sigqueue函数发送信号,以及通过signal和sigaction函数注册并响应信号。示例代码展示了如何在父子进程中通过信号进行通信,实现进程同步和数据交换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天要分享的是Linux中的信号机制,信号是一种软件中断,是一种处理异步事件的方法,可以很好地在多个进程之间进行同步和简单的数据交换。 一、发送信号发送信号通常有三种方式,分别是使用kill、raise、sigqueue函数1、kill函数
int kill(pid_t pid,int sig);
第一个参数代表向谁发送,第二个参数代表发送什么信号。调用成功返回0,调用失败返回-1.2、raise函数
int raise(int sig);
这个是向自身发送一个信号,等价于
kill(getpid(),sig);
3、sigqueue函数
int sigqueue(pid_t pid,int sig,const union sigval value);
其中第三个参数的形式为
typedef union sigval{int sival_int;void *sival_ptr;}sigval_t;
这个函数除了能发送信号之外,还能携带一些参数,这些参数就保存在共用体里面。下面写一个简单的代码
#include#include#include#include #include int main(int argc,char* argv[]){    pid_t pid;    pid=fork();    if(pid==0){        printf("This is child process\n");        sleep(10);        printf("does't receive abort signal\n");    }    else{        printf("This is parent process\n");        sleep(5);        if(kill(pid,SIGABRT)==-1){            printf("kill function failed\n");        }    }    return 0;}
在这里使用fork创建了一个子进程,子进程本来调用sleep函数要睡眠10秒,但是父进程在睡眠5秒后向子进程发送一个中止的信号,导致子进程在5s时中止了。从下面的图中也可以看到原来两个进程都是处于睡眠态,后面就结束了进程。

cf66d084f745bbf3d6431dfbdea3179d.png

二、信号的注册和响应前面讲了三种发送信号的方式,但是光发送信号还不够,对于接收方来说,还得对信号进行处理。一般可以使用signal函数和sigaction函数来注册信号。1、signal函数
void (*signal(int signum,void(*handler)(int)))(int);
这个函数原型看起来很复杂,可以难倒很多人,我们可以对他进行简化:
typedef void (*sighandler_t)(int);sighandler_t signal(int signum,sighandler_t handler);
这样就清楚很多了。首先看sighandler_t他是一个函数指针,输入参数是int类型,无返回值。再看signal这个函数,他有两个输入参数,第一个是int类型,第二个是一个函数指针,另外,他返回的也是一个函数指针。只有对函数指针非常熟悉,才能看懂上面这个表达式。如果还是不懂,可以对比下面这个表达式
char* function(int a,char* b);
这个应该很容易看出是一个函数了吧,两个输入参数,返回一个char*。如果这个可以看懂,那么上面那个其实是类似的,只不过他不是char* ,而是一个 函数指针类型:void(*)(int).signal函数的第一个参数是信号类型,第二个参数是函数指针,也就是跳转到哪里去执行。也就是说,当收到第一个参数表示的信号之后,就会跳转到第二个参数指向的代码段去执行。2、sigaction函数
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 是一个函数指针,其含义与 signal 函数中的信号处理函数类似。成员sa_sigaction 则是另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。当 sa_flags 成员的值包含了 SA_SIGINFO 标志时,系统将使用 sa_sigaction 函数作为信号处理函数,否则使用 sa_handler 作为信号处理函数。接下来写一个简单的代码,来应用一下上面的几个函数。实现的需求就是创建一个子进程,父进程每隔一秒钟向子进程发送一个信号,子进程收到信号之后往一个txt文档中写入一句话。
#include#include#include#include #include #include #include #include void signalDeal(int sig,siginfo_t *info,void*t);int fg=0;int main(int argc,char* argv[]){    if(argc!=2){        printf("please input param\n");        return -1;    }    char writebuff[]="This is a test\n";    int count=0,seektemp=0,j=0;   int fd=open(argv[1],O_RDWR | O_CREAT,S_IRWXU);       //open a file   pid_t pid=fork();   if(pid==0)                            //child process   {        struct sigaction act;        act.sa_sigaction=signalDeal;        sigemptyset(&act.sa_mask);        act.sa_flags=SA_SIGINFO;        sigaction(SIGUSR1,&act,NULL);           while(1)       {        while(!fg);        fg=0;        if(count==0){                         //first write            int ret=write(fd,writebuff,strlen(writebuff));            if(ret==-1){                printf("write failed\n");            }            seektemp=lseek(fd,0,SEEK_CUR);            count++;        }        else{                                 //not first write            j=strlen(writebuff)*count;             //offset            seektemp=lseek(fd,j,SEEK_SET);            int ret=write(fd,writebuff,strlen(writebuff));            if(ret==-1){                printf("write failed\n");            }            count++;        }       }          }   else {                               //parent process                while(1)        {            sleep(1);            int ret=kill(pid,SIGUSR1);            if(ret==-1){                printf("send signal failed\n");            }            else{                printf("send signal success\n");            }        }           }}void signalDeal(int sig,siginfo_t *info,void*t){    if(sig==SIGUSR1)    {        fg=1;    }}
在命令行输入
gcc test.c./a.out a.txt
之后可以看到生成了一个a.txt文档,并且文档里有我们写入的内容

0527ec29855eb1a38f185d396c007281.png

a548d935d582b03cc7ce56bcd40ad9ed.png

b6daf51b91baf3e034fd0cf8c566f580.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值