Linux进程通信——信号(二)

目录

信号处理函数的注册

信号处理发送函数

sigaction函数

作用

头文件

函数原型

参数解读

struct sigaction结构体

函数原型

参数解读

sigqueue函数

作用

头文件

函数原型

参数解读

union sigval联合体

注意事项

代码示例


信号处理函数的注册

信号处理函数的注册不只一种方法,分为入门版和高级版
1.入门版: 函数 signal
2.高级版:函数 sigection

信号处理发送函数

信号发送函数也不止一个,同样分为入门版和高级版
1.入门版: 函数 kill
2.高级版: 函数 sigqueue

sigaction函数

作用

sigaction函数是一个系统调用,可以用来查询或设置信号处理方式

头文件

#include <signal.h>

函数原型

int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);

参数解读

signum参数指出要捕获的信号类型
act参数指定新的信号处理方式,struct sigaction类型如果不为空说明需要对该信号有新的配置(函数原型是指针,输入参数时应输入地址)
oldact

备份

1.如果不为空,那么可以对之前的信号配置进行备份,以方便之后进行恢复

2.如果为空,直接输入NULL

struct sigaction结构体

函数原型

struct sigaction
{
   void (*sa_handler)(int); //信号处理程序,不接受额外数据,SIG_IGN 为忽略,SIG_DFL 为默认动作
   void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序,能够接受额外数据和sigqueue配合使用
   sigset_t sa_mask;//阻塞关键字的信号集,可以再调用捕捉函数之前,把信号添加到信号阻塞字,信号捕捉函数返回之前恢复为原先的值。
   int sa_flags;//影响信号的行为SA_SIGINFO表示能够接受数据
 };
//若调用该结构体,则sa_handler和sa_sigaction只能选择其中一个,即两个不能同时存在

参数解读

sa_handler:与前一章节中的handler相同,代表新的信号处理函数,但不能接受额外数据。

sa_sigaction:信号处理程序,代表新的信号处理函数,能够接受额外数据,需配合sigqueue函数

int这里的int一般是信号函数类型(编号),如int signum
siginfo_t *用于接受信号,功能比较多样化,如siginfo_t *info
void *接收到信号所携带的额外数据,是否为NULL可以判断是否携带额外数据,如void *context

siginfo为结构体,其中后面跟的是指针,在调用时应注意结构体指针的书写格式(->),下面是该结构体的具体成员。

 siginfo_t
{
               int      si_signo;    /* Signal number */
               int      si_errno;    /* An errno value */
               int      si_code;     /* Signal code */
               int      si_trapno;   /* Trap number that caused
                                        hardware-generated signal
                                        (unused on most architectures) */
               pid_t    si_pid;      /* Sending process ID */
               uid_t    si_uid;      /* Real user ID of sending process */
               int      si_status;   /* Exit value or signal */
               clock_t  si_utime;    /* User time consumed */
               clock_t  si_stime;    /* System time consumed */
               sigval_t si_value;    /* Signal value */
               int      si_int;      /* POSIX.1b signal */
               void    *si_ptr;      /* POSIX.1b signal */
               int      si_overrun;  /* Timer overrun count; POSIX.1b timers */
               int      si_timerid;  /* Timer ID; POSIX.1b timers */
               void    *si_addr;     /* Memory location which caused fault */
               int      si_band;     /* Band event */
               int      si_fd;       /* File descriptor */
}

其中的成员很多,si_signosi_code 是必须实现的两个成员。可以通过这个结构体获取到信号的相关信息
关于发送过来的数据是存在两个地方的,sigval_t si_value这个成员中有保存了发送过来的信息;
同时,在si_int或者si_ptr成员中也保存了对应的数据。

sa_mark:用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置

调用该函数后,会在捕捉函数调用前设置为阻塞,并在捕捉函数返回时恢复默认原有设置。这样的目的是,在调用信号处理函数时,就可以阻塞默写信号了。在信号处理函数被调用时,操作系统会建立新的信号阻塞字,包括正在被递送的信号。因此,可以保证在处理一个给定信号时,如果这个种信号再次发生,那么他会被阻塞到对之前一个信号的处理结束为止

sa_flags:用来设置信号处理的其他相关操作,下列的数值可用

SA_RESETHAND当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
SA_RESTART如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
SA_NODEFER一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号

但由于我们需要接受数据,所以这里我们经常使用的数值是SA_SIGINFO

sigqueue函数

作用

在队列中向指定进程发送一个信号和数据

头文件

#include <signal.h>

函数原型

int sigqueue(pid_t pid, int sig, const union sigval value);

参数解读

pid信号发送目标位置的进程号,可用ps查看或者直接调用getpid()打印出来
sig所发送的信号类型,如SIGUUSR1
value信号附带的数据,即传送的内容是什么,是一个联合体

union sigval联合体

union sigval
{
   int   sival_int;//传递的数据可以是整型数
   void *sival_ptr;//指向要传递的信号参数
 };

注意事项

1、使用 sigaction 函数安装信号处理程序时,需先写入 SA_SIGINFO 标志才可以接受数据。
2、sigaction 结构体中的sa_sigaction成员提供了信号捕捉函数。如果实现的sa_handler成员,那么将无法获取额外携带的数据
3、sigqueue 函数只能把信号发送给单个进程,可以使用 value 参数向信号处理程序传递整数值或者指针值。

代码示例

sigcation.c

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

void handler(int signum,siginfo_t *info,void *context)
{
	printf("the signum is %d\n",signum);
	if(context != NULL)//信号携带内容,将内容打印出来
	{
		printf("get context is %d\n",info->si_int);//内容为整型数,整型数打印有两种方法 第一种是直接打印整型数,第二种是调用共用体中的整型数打印
		printf("get context is %d\n",info->si_value.sival_int);
		printf("send pid is %d\n",info->si_pid);
	}
}

int main()
{
	struct sigaction act;

	printf("pid is %d\n",getpid());	

	act.sa_sigaction = handler;//信号处理函数调用
	act.sa_flags = SA_SIGINFO;//设置为可接收数据
	
	sigaction(SIGUSR1,&act,NULL);//第二个参数是指针,应输入地址,第三个参数是备份,不需要则写入NULL

	while(1);
	return 0;
}

sigqueue.c

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

int main(int agrc,char **agrv)
{
	int pid = atoi(agrv[1]);
	int signum =atoi(agrv[2]);

	union sigval value;
	value.sival_int = 999;//信号内容设置为999

	sigqueue(pid,signum,value);

	printf("pid is %d\n",getpid());
	puts("done");
	return 0;
}

先将sigaction.c的进程号打印出来后会等待接受数据,接着调用sigqueue.c将其自身进程号打印出来,并做信号处理,将携带内容发送至sigaction.c,sigaction.c接受到数据后将数据打印出来。实现了在一端发送信号,在另一端接收信号。

  • 22
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值