万网网站备案证书,黄冈市建设工程信息网,音乐网站建设教程视频教程,桥梁建设网站在哪里可以投稿信号也是IPC中的一种#xff0c;是和管道#xff0c;消息队列#xff0c;共享内存并列的概念。 本文参考#xff1a; Linux中的信号_linux中信号_wolf鬼刀的博客-CSDN博客 Linux系统编程#xff08;信号处理 sigacation函数和sigqueue函数 )_花落已飘的博客-CSDN博客 Linu…信号也是IPC中的一种是和管道消息队列共享内存并列的概念。 本文参考 Linux中的信号_linux中信号_wolf鬼刀的博客-CSDN博客 Linux系统编程信号处理 sigacation函数和sigqueue函数 )_花落已飘的博客-CSDN博客 Linux的sigqueue函数_linux sigqueue_QtHalcon的博客-CSDN博客 概念
信号是进程之间异步通知的一种方式属于软中断
可以使用“kill -l”来查看系统定义的信号列表 所以当在终端输入“crtl c”时其实就是调用了2号SIGINT使用信号机制停止了一个程序。 从图中可以看到每个信号都有一个编号和宏定义的名称这些宏都可以在signal.h中找到注意并不是一共有64个信号自己仔细看共有62种信号31号信号之前都是不可靠信号也是非实时信号编号34以上的是实时信号可靠信号各种信号各自在什么条件下产生什么默认的动作都可以在signal7中查看 同时kill命令还可以用来执行命令例如一个进程的PID号为1234则可以使用“kill 9 1234”或“kill SIGKILL 1234” 来杀死这个进程。 另外kill不仅可以使用在命令窗口kill还可以作为一个API kill函数 给一个指定的进程发送一个指定的信号 包含的头文件 #include sys/types.h
#include signal.h 函数原型 int kill(pid_t pid, int sig); 函数参数 pid进程号sig信号编号 信号的处理方式
忽略信号SIGKILL和SIGSTOP无法被忽略执行给信号的默认动作提供一个信号处理函数要求用户在处理该信号时切换到用户态去执行处理函数即捕捉信号
其中对于用户来说信号更多的意义是实现异步操作也就是捕捉信号其核心就是编写“信号处理函数” 信号处理的API函数及应用
signal函数
用来自定义信号处理方式
需要包含的库
#include signal.h
函数原型
typedef void (*sighandler_t)(int); //一个指向“传入参数是int 返回值是void的函数”名为“sighandler_t”的指针sighandler_t signal(int signum, sighandler_t handler);
函数参数
signum信号编号handler函数指针指向信号处理函数也可以使用宏比如使用“SIG_IGN”则忽略信号
使用举例1
signal1.c
#include signal.h
#include stdio.hvoid sighandler(int sig)
{printf(get signal:%d\n,sig);}int main()
{signal(2,sighandler);while(1);return 0;
} 可见当捕获了信号2之后在键盘输入“ctrl c” 不再会执行默认动作来结束进程而是被程序捕获并执行了信号处理函数。
那么此时如何退出进程呢可以使用刚刚提到的kill指令先搜索pid号然后直接杀死进程 使用举例2
同样也可以在程序中直接调用kill函数来发送信号
signal2.c 编写一个C程序实现“向自己发送指定信号”的功能 #include signal.h
#include stdio.h
#include sys/types.h
#include unistd.h
#include stdlib.hvoid sighandler(int sig)
{printf(get signal:%d\n,sig);}int main(int argc,char **argv)
{int signum;pid_t pid;signum atoi(argv[1]); //由于从键盘接收的是字符串所以要使用“atoi”函数将ASCII码转为整型数pid getpid();signal(2,sighandler); //为了实现效果一定要先执行signal再执行killkill(pid,signum);while(1);return 0;
}
编译运行代码并指定第二个参数为2 可见虽然此时没有在键盘打出 “ctrl c”但是内部的代码调用了kill对自己发送了2号信号所以同样实现了刚刚的效果。 学到了这里一定会产生疑问为什么信号会作为IPC中的一员如果只是发送信号的话不应该算是一种很有效的进程通讯方式所以信号的处理还有更高级的方法也就是带消息的高级信号操作既然要带消息那么就需要使用更高级的API函数来实现收发 发送信号使用sigqueue函数接收信号使用sigaction函数 sigaction函数
实现带消息的高级信号操作可以接收带消息的信号
需要包含的库
#include signal.h
函数原型
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
函数参数
signum信号编号act指定新的信号处理方式oldact输出先前信号的处理方式如果不为NULL的话
struct sigaction结构体介绍sigaction函数的第二个参数
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()的参数handler相同代表新的信号处理函数如果使用这个成员参数那就和signal函数无异了sa_sigaction带消息的信号处理函数 int第一个参数是信号编号 siginfo_t *第二个参数是一个结构体包括si_signosi_codesi_intsi_value等等各种成员其中si_signo和si_code必须实现 void *第三个参数是一个指针用来指示是否有消息存在如果为NULL则无消息否则就有消息 sa_mask用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置可以理解为处理信号的时候释放阻塞默认阻塞sa_flags用来设置信号处理的其他相关操作可以是以下值的“按位或”组合 ◆ SA_RESTART使被信号打断的系统调用自动重新发起 ◆ SA_NOCLDSTOP使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号 ◆ SA_NOCLDWAIT使父进程在它的子进程退出时不会收到 SIGCHLD 信号这时子进程如果退出也不会成为僵尸进程 ◆ SA_NODEFER使对信号的屏蔽无效即在信号处理函数执行期间仍能发出这个信号 ◆ SA_RESETHAND信号处理之后重新设置为默认的处理方式 ◆ SA_SIGINFO使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数重要 re_restorer是一个已经废弃的数据域不使用 sigqueue函数
发送带消息的信号 成功使用sigqueue这个函数需要有两个前提 sigaction函数的第二个参数结构体中的sa_flags成员必须有“SA_SIGINFO”sigaction函数的第二个参数结构体中实现的是成员sa_sigaction函数而不是成员sa_handler函数 需要包含的库
#include signal.h
函数原型
int sigqueue(pid_t pid, int sig, const union sigval value);
函数参数
pid目标进程的进程号sig要发送的信号的编号value要附带发送的消息 value的类型是一个名为sigval的联合体如果需要附带的消息是整型则将数据存入成员“sival_int”而如果消息类型是字符串则存入成员“sival_ptr union sigval {int sival_int;void *sival_ptr;
};使用sigaction和sigqueue的实操演示
需求编写两个C程序一个使用sigaction来接收一个使用sigqueue来发送实现带消息的信号的通讯
signal3.c接收带消息的信号
#include signal.h
#include stdio.h
#include sys/types.h
#include unistd.h
#include stdlib.hvoid sighandler(int sig, siginfo_t *info, void *context)
{printf(get signal:%d\n,sig);if(context ! NULL){printf(get data %d\n,info-si_int);//printf(get data %d\n,info-si_value.sival_int);}}int main()
{struct sigaction act;act.sa_sigaction sighandler;act.sa_flags SA_SIGINFO;sigaction(2,act,NULL);while(1);return 0;
}
signal4.c发送带消息的信号
#include signal.h
#include stdio.h
#include sys/types.h
#include unistd.h
#include stdlib.hint main(int argc,char **argv)
{int signum;pid_t pid;int data;pid atoi(argv[1]);signum atoi(argv[2]);data atoi(argv[3]);union sigval value;value.sival_int data; sigqueue(pid,signum,value);printf(signal no.%d has been sent to pid %d, context:%d\n,signum,pid,data);return 0;
}
实现效果 首先编译并运行signal3.c 可见此时没有接收到任何信号一直阻塞
此时新开一个窗口先查询到这个signal3.c的进程号
然后根据进程号编译并运行signal4.c将编号为2的信号发送到signal3.c对应的进程并附带55的整型消息 此时再回看signal3.c的运行界面 可见此时不仅收到了来自signal4.c的信号还收到了附带的整型数据消息