Linux-信号
信号是由用户,系统或者进程发送给目标进程的信息,以通知目标进程某个状态的改变或系统异常。
进程分为前台进程和后台进程,对于前台进程我们可以输入特殊的终端字符来给它发送信号,比如输入Ctrl+c,发送一个中断信号
系统异常,比如浮点异常和非法内存段访问
运行kill命令或者调用kill函数
发送信号
Linux下,一个进程给一个进程发送信号的api是kill函数
int kill(pid_t pid,int sig);
sig是指定的信号,pid是指定的进程
pid>0 信号发送给指定的进程
pid=0. 信号发送给进程组的其他进程
pid=-1 信号发送给除init进程外的所有进程
pid<-1 信号发送给组ID为-pid的进程组中的所有成员
有发送信号,那肯定得有一个接收信号的东西
接收信号
signal系统调用
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signum是信号的种类
这里我们可以写数字也可以写具体的名称
handler是一个函数指针,传入函数名就行
下面实现一个信号的安装和发送
void handle(int v)
{
cout << "信号被触发.." << v << endl;
}
void demo4()
{
int pid = 0;
pid = fork();
if (pid > 0)
{
// 信号安装
signal(SIGUSR1, handle);
while (1)
;
}
else if (pid == 0)
{
// 发送信号
sleep(1);
kill(getppid(), SIGUSR1);
while (1)
;
}
}
父进程进行信号安装,子进程进行信号的发送
带参信号函数
上面的是简单的信号发送,但是不能带参数,只能是发送一个信号过去
sigaction系统调用
#include
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
安装信号的函数变了,那么发送信号的函数也应该发生变化
#include
int sigqueue(pid_t pid, int sig, const union sigval value);
前两个参数就不用说了,主要是最后一个是一个联合体
union sigval {
int sival_int;
void *sival_ptr;
};
填对应的参数就行了
下面来一个带参数的信号发送和接收
void demo5_handel(int v, siginfo_t *info, void *context)
{
cout << "v:" << v << endl;
cout << "value:" << info->si_value.sival_int << endl;
}
void demo5()
{
int pid = 0;
pid = fork();
if (pid == 0) // 子进程,安装
{
struct sigaction action;
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = demo5_handel;
sigaction(SIGUSR1, &action, NULL);
while (1)
;
}
else if (pid > 0) // 父进程,发送
{
sleep(1);
union sigval val;
val.sival_int = 10000;
sigqueue(pid, SIGUSR1, val);
while (1)
;
}
}
下面来一个难一点的demo
有ABCD四个进程
A携带数据1000通过SIGUSR1发给进程B
B收到数据以后对数据进行+1操作再次携带数据1001通过SIGUSR2发给进程C
C收到数据以后对数据进行+1操作再次携带数据1002通过SIGRTMIN发给进程D
D收到数据以后对数据进行+1操作再次携带数据1003通过SIGUSR2发给进程A
A收到数据以后将最终的数据打印到控制台
首先我的思想是主进程为A,A创建B进程,B创建C,依此下去,这里我们使用一个信号函数,对于信号的区分我们在代码中理解
zh
int fatherpid;
int childpid;
void handel_(int signo,siginfo_t *info,void *context)
{
if(signo==SIGUSR2)
{
if(fatherpid==0)
{
cout<<"进程A收到SIGUSR2信号 value="<si_value.sival_int<