背景介绍
多进程之间的同步机制:信号量。而在多线程编程中,通常更常见的是使用线程之间的同步机制,例如互斥锁、条件变量、信号量等,来实现线程之间的协调和通信。这些机制更适合用于线程级别的同步和通信需求。
POSIX信号
信号(signal)就是告知某一进程发生了某个事件的通知,有时也称为软件中断(software interrupt)。
信号通常是 异步
发生的,也就是说:进程预先不知道信号的准确发生时刻。
信号发送方式:
1)由一个进程发送给另一个进程(或自身)
2)由内核发送给某个进程
一般来说某一个进程需要定义一个信号回调函数用来等待一个特定信号的到来,只要有特定信号发生,信号处理函数就会被调用。一个signal()只能针对某一信号的处理,若要处理多个信号就要注册多个signal()
每一个信号都有一个名字,这些名字都是以SIG开头,且信号名被定义为正整数常量。不同的操作系统所能支持的信号数量都有不同。
在某个信号出现时,可以告诉内核按下列3种方式之一进行处理,我们称之为信号的处理或与信号相关的动作。
1)忽略此信号。大多数信号都可以使用这种方式进行处理,但 SIGKILL
和 SIGSTOP
不能被忽略。
2)捕捉信号。SIGKILL
和 SIGSTOP
不能被捕捉
3)执行系统默认动作。对于大多数信号的系统默认动作时终止进程。
信号表:
名字 | 说明 | Linux 3.2.0 | 默认动作 |
---|---|---|---|
SIGABRT |
异常终止(abort) | yes | 终止+core |
SIGALRM | 定时器超时(alarm) | yes | 终止 |
SIGBUS | 硬件故障 | yes | 终止+core |
SIGCHLD |
子进程状态改变 | yes | 忽略 |
SIGCONT | 使暂停进程继续 | yes | 继续/忽略 |
SIGEMT | 硬件故障 | yes | 终止+core |
SIGFPE |
算术异常 | yes | 终止+core |
SIGHUP | 连接断开 | yes | 终止 |
SIGILL | 非法硬件指令 | yes | 终止+core |
SIGINT |
终端中断符 | yes | 终止 |
SIGIO | 异步I/O | yes | 终止/忽略 |
SIGIOT | 硬件故障 | yes | 终止+core |
SIGKILL |
终止 | yes | 终止 |
SIGPIPE | 写至无读进程的管道 | yes | 终止 |
SIGPOLL | 可轮询事件(poll) | yes | 终止 |
SIGPROF | 梗概事件超时(setitimer) | yes | 终止 |
SIGPWR | 电源失效/重启动 | yes | 终止+core |
SIGQUIT | 终端退出符 | yes | 终止+core |
SIGSEGV | 无效内存引用 | yes | 终止+core |
SIGSTKFLT | 协处理器栈故障 | yes | 终止 |
SIGSTOP |
停止 | yes | 停止进程 |
SIGSYS | 无效系统调用 | yes | 终止+core |
SIGTERM | 终止 | yes | 终止 |
SIGTRAP | 硬件故障 | yes | 终止+core |
SIGTSTP | 终端停止符 | yes | 停止进程 |
SIGTTIN | 后台读控制 tty | yes | 停止进程 |
SIGTTOU | 后台写向控制 tty | yes | 停止进程 |
SIGURG | 紧急情况(套接字) | yes | 忽略 |
SIGUSR1 |
用户定义信号 | yes | 终止 |
SIGUSR2 |
用户定义信号 | yes | 终止 |
SIGVTALRM | 虚拟事件闹钟(setitimer) | yes | 终止 |
SIGWINCH | 终端窗口大小改变 | yes | 忽略 |
SIGXPU | 超过CPU限制(setrlimit) | yes | 终止或终止+core |
SIGXFSZ | 超过文件长度限制(setrlimit) | yes | 终止或终止+core |
signal()
/* 包含的头文件 */
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler); // 若出错,返回SIG_ERR
kill进程发送信号
测试SIGUSR1、SIGUSR2、SIGINT信号的捕获:
sig_usr.c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <signal.h>
static void sig_usr(int signo)
{
if (signo == SIGUSR1)
printf("received SIGUSR1\n");
else if (signo == SIGUSR2)
printf("received SIGUSR2\n");
else if (signo == SIGINT)
printf("received SIGINT\n");
else
printf("received signal %d\n", signo);
}
int main(void)
{
if (signal(SIGUSR1, sig_usr) == SIG_ERR)
{
printf("can't catch SIGUSR1\n");
}
if (signal(SIGUSR2, sig_usr) == SIG_ERR)
{
printf("can't catch SIGUSR2\n");
}
if (signal(SIGINT, sig_usr) == SIG_ERR)
{
printf("can't catch SIGINT\n");
}
while (true)
{
pause();
}
exit(0);
}
子进程结束发送信号
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
static int g_running = 0;
static int handle(void)
{
int second = 5;
printf("sleep 5s");
while (second--)
{
printf(".");
fflush(stdout);
sleep(1);
}
printf("\n");
return 0;
}
static void sig_handler(int signo)
{
pid_t pid;
while (1)
{
pid = waitpid(-1, NULL, WNOHANG);
if (pid > 0)
{
printf("child %d terminated\n", pid);
g_running = 0;
}
if (pid == -1 || pid == 0)
{
break;
}
}
}
int main(void)
{
g_running = 1;
if (signal(SIGCHLD, sig_handler) == SIG_ERR)
{
printf("can't catch SIGCHLD\n");
exit(1);
}
int pid = 0;
pid = fork();
if (pid < 0)
{
printf("fork error\n");
exit(1);
}
else if (pid == 0)
{
handle();
exit(1);
}
while (g_running)
{
pause();
}
pid_t pidMain;
pidMain = getpid();
printf("main %d exit\n", pidMain);
exit(0);
}
标签:core,信号量,POSIX,信号,printf,终止,yes,include
From: https://www.cnblogs.com/caojun97/p/17753861.html