sigaction
sigaction 函数主要用于在一个进程内部对信号进行处理和管理。它允许进程注册自定义的信号处理函数,来应对接收到的信号。在多线程编程中,sigaction 函数也可以用于线程中对信号的处理。虽然信号是进程级别的通信机制,但在某些情况下,线程也可以捕获和处理信号。
sigaction原型:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
signum:要操作的信号编号;
act:新的信号处理方式,包括信号处理函数、信号掩码、标志等;
oldact:旧的信号处理方式。
注册信号处理函数:每个线程可以通过sigaction 函数注册自己的信号处理函数,以捕获特定信号。以下是注册信号处理函数的一般步骤:
#include <signal.h>
void sig_handler(int signum) {
// 处理信号的代码
}
struct sigaction sa;
sa.sa_handler = sig_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
// 注册信号处理函数
if (sigaction(SIGINT, &sa, NULL) == -1) {
perror("Error registering signal handler");
exit(1);
}
在上述例子中,我们定义了一个名为sig_handler的信号处理函数。通过sigaction 函数,我们将SIGINT信号的处理函数设置为sig_handler。
注意:各线程独立处理信号:在多线程环境中,每个线程可以独立注册和处理信号。这意味着当某个线程捕获到信号时,其他线程不会被此信号打断。
pthread_sigmask
该函数与sigprocmask()不同的是,一般采用pthread_mask来屏蔽或者解除某个线程对某个信号的处理。具体用法是将自定义信号集设置给阻塞信号集(blocked
位向量)。
int pthread_sigmask (int how, const sigset_t *newmask, sigset_t *oldmask);
1.how:表示对信号屏蔽字的修改方式,有以下几种取值:
SIG_BLOCK:将set中指定的信号添加到线程的信号屏蔽字中,即屏蔽这些信号,即追加屏蔽字。
SIG_UNBLOCK:将set中指定的信号从线程的信号屏蔽字中移除,即允许接收这些信号。
SIG_SETMASK:将set中指定的信号设置为线程的新信号屏蔽字,即覆盖原屏蔽字。
2.set:指向一个sigset_t类型的信号集,用于指定需要修改/设置的信号。
3.oldset:指向一个sigset_t类型的信号集,用于存储修改前的旧信号屏蔽字。如果不需要保存旧的信号屏蔽字,可以传入NULL。
pthread_kill
该函数用于向指定的线程发送信号。
int pthread_kill(pthread_t thread, int sig);
函数参数的含义如下:
thread
: 要发送信号的目标线程的标识符。pthread_t
类型是一个线程标识符的数据类型,通常是一个无符号整数。可以通过pthread_create
创建线程时返回的线程标识符或使用pthread_self
函数获取当前线程的标识符。sig
: 要发送的信号的编号。可以是标准的POSIX信号编号,如SIGUSR1
、SIGUSR2
等,也可以是其他自定义的信号编号。
函数返回值:
如果成功发送信号,则返回0。如果发生错误,则返回相应的错误代码。
在使用pthread_kill
函数发送信号时需要注意以下几点:
- 信号只能发送给同一进程中的其他线程,不能发送给不同进程的线程。
- 接收到信号的线程需要先设置相应的信号处理函数,以便在接收到信号时执行相应的操作。
- 如果线程在设置了信号处理函数之前收到了信号,信号会被默认处理。
示例:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
void signal_handler(int signal) {
printf("Received signal: %d\n", signal);
printf("Terminating the current thread...\n");
pthread_exit(NULL);
}
void* thread_func(void* arg) {
// 设置信号屏蔽字
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
// 注册信号处理函数
signal(SIGINT, signal_handler);
// 等待信号
int received_signal;
sigwait(&mask, &received_signal);
printf("Signal received: %d\n", received_signal);
// 解除信号屏蔽
pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
return NULL;
}
int main() {
// 创建线程
pthread_t thread;
if (pthread_create(&thread, NULL, thread_func, NULL) != 0) {
fprintf(stderr, "Failed to create thread\n");
return 1;
}
// 在一段时间后向子线程发送SIGINT信号
sleep(5);
pthread_kill(thread, SIGINT);
// 等待线程结束
pthread_join(thread, NULL);
return 0;
}
子线程首先使用pthread_sigmask
将SIGINT
信号添加到信号屏蔽字中,阻塞SIGINT
信号的传递。然后,子线程注册了信号处理函数signal_handler
用来处理SIGINT
信号。子线程通过调用sigwait
函数来等待信号的到达。当SIGINT
信号到达时,sigwait
函数会返回,并将信号值存储在received_signal
变量中。接着,子线程使用pthread_sigmask解除信号屏蔽,允许后续SIGINT
信号的传递。