pthread_sigmask的用法及注意事项,给一个c的示例

pthread_sigmask 用于设置线程的信号掩码,控制线程接收哪些信号。以下为详细用法、注意事项及示例代码:


用法

1
2
#include <signal.h>
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
  • 参数
    • how:操作类型,取值为 SIG_BLOCK(阻塞指定信号)、SIG_UNBLOCK(解除阻塞)或 SIG_SETMASK(直接设置掩码)。
    • set:要操作的信号集合。
    • oldset:返回旧的信号掩码,可为 NULL
  • 返回值:成功返回 0,失败返回错误码。

注意事项

  1. 线程独立性:每个线程有独立的信号掩码,新线程继承创建者的掩码。
  2. 专用信号线程:建议在专用线程中通过 sigwait 处理信号,其他线程阻塞相关信号。
  3. 信号竞争:确保信号处理线程在信号被阻塞后启动,避免竞态条件。
  4. 初始化信号集:使用 sigemptysetsigaddset 初始化信号集合。
  5. 错误检查:检查 pthread_sigmask 的返回值以确保成功。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>

// 信号处理线程函数
void* signal_handler(void *arg) {
sigset_t *set = (sigset_t*)arg;
int sig;
while (1) {
// 等待信号到达
if (sigwait(set, &sig) {
perror("sigwait failed");
break;
}
printf("Received signal: %d\n", sig);
if (sig == SIGINT) { // 处理 Ctrl+C
printf("Exiting...\n");
break;
}
}
return NULL;
}

int main() {
pthread_t tid;
sigset_t set;

// 初始化信号集:阻塞 SIGINT 和 SIGTERM
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGTERM);

// 设置主线程信号掩码
if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
perror("pthread_sigmask failed");
return 1;
}

// 创建专用信号处理线程
if (pthread_create(&tid, NULL, signal_handler, &set) != 0) {
perror("pthread_create failed");
return 1;
}

// 主线程继续工作
printf("Main thread running. Press Ctrl+C to exit.\n");
pthread_join(tid, NULL); // 等待信号线程结束
printf("Main thread exits.\n");
return 0;
}

代码说明

  1. 主线程
    • 阻塞 SIGINTSIGTERM,确保它们不会触发默认行为(如终止进程)。
    • 创建专用线程处理信号。
  2. 信号处理线程
    • 使用 sigwait 同步等待信号,避免异步信号处理的复杂性。
    • 收到 SIGINT(如 Ctrl+C)时退出循环,线程结束。

运行示例

  1. 编译代码:
    1
    gcc example.c -lpthread -o example
  2. 运行程序:
    1
    ./example
  3. 按下 Ctrl+C 触发 SIGINT,程序输出:
    1
    2
    3
    Received signal: 2
    Exiting...
    Main thread exits.

通过合理使用 pthread_sigmask,可以实现线程安全的信号处理机制,避免多线程环境下的信号竞争问题。