Linux--信号阻塞与屏蔽

1. sigprocmask函数提供屏蔽和解除屏蔽信号的功能。 
从而实现关键代码的运行不被打断。 
函数声明如下:

  int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
其中参数 how可设置的参数为:SIG_BLOCK, SIG_UNBLOCK,SIG_SETMASK 
SIG_BLOCK: 
按照参数 set 提供的屏蔽字,屏蔽信号。并将原信号屏蔽保存到oldset中。 
SIG_UNBLOCK: 
按照参数 set 提供的屏蔽字进行信号的解除屏蔽。针对Set中的信号进行解屏。 
SIG_SETMASK: 
按照参数 set 提供的信号设置重新设置系统信号设置。

2. 信号屏蔽与解屏常见实现 
方法一: SIG_BLOCK, SIG_UNBLOCK成对实现 
优点oldset可以不管。

方法二: 
SIG_BLOCK设置屏蔽,保存原有信号设置。 
SIG_SETMASK重新恢复原有设置。

3. 屏蔽过程中接受到的信号如何处理 
在信号屏蔽过程中,出现的所有被屏蔽的信号,不管发生多少次,在信号解除屏蔽后,系统会执行一次被屏蔽信号上的操作。

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
 
int flag_sigusr1 = 0;
int flag_sigusr2 = 0;
 
void sig_usr1(int signo)
{
    fprintf(stdout, "caught SIGUSR1\n");
    flag_sigusr1 = 1;
    return;
}
 
void sig_usr2(int signo)
{
    fprintf(stdout, "caught SIGUSR2\n");
    flag_sigusr2 = 1;
    return;
}
 
int main(void){
    sigset_t newmask, oldmask;
    signal(SIGUSR1, sig_usr1);
    signal(SIGUSR2, sig_usr2);
 
    fprintf(stdout, "catch sigusr1 can break\n");
     
    while(1)
    {
        if(flag_sigusr1)
        {
            fprintf(stdout, "break\n");
            break;
        }
        sleep(5);
    }
    fprintf(stdout, "first while was broken\n");
     
    //重新设置为0
    flag_sigusr1 = 0;
    flag_sigusr2 = 0;
 
    // block SIGUSR1
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGUSR1);
    if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
    {
        perror("sigprocmask error");
    }
 
    fprintf(stdout, "only catch sigusr2 can break, because sigusr1 has been blocked\n");
    while(1)
    {
        if(flag_sigusr1 || flag_sigusr2)
        {
            fprintf(stdout, "break\n");
            break;
        }
        sleep(5);
    }
    fprintf(stdout, "second while was broken\n");
     
    fprintf(stdout, "after second while was broken, flag_sigusr1=%d, flag_sigusr2=%d\n", flag_sigusr1, flag_sigusr2);
 
    return 0;
}

  

多线程情况下每个线程共用信号处理函数,但是每个线程可以选择自己是否block某个信号。

再看一个多线程的例子:子线程的功能同上,主线程接收到hup信号会向子线程发送usr2信号。

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<pthread.h>
 
int flag_sigusr1 = 0;
int flag_sigusr2 = 0;
int flag_sighup  = 0;
 
void sig_usr1(int signo)
{
    fprintf(stdout, "sig|caught SIGUSR1\n");
    flag_sigusr1 = 1;
    return;
}
 
void sig_usr2(int signo)
{
    fprintf(stdout, "sig|caught SIGUSR2\n");
    flag_sigusr2 = 1;
    return;
}
 
void sig_hup(int signo)
{
    fprintf(stdout, "sig|caught SIGHUP\n");
    flag_sighup = 1;
    return;
}
 
void *thread_control_signal(void *arg)
{
    sigset_t newmask, oldmask;
    sigemptyset(&newmask);
 
    //thread block sighup
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGHUP);
    if(pthread_sigmask(SIG_BLOCK, &newmask, &oldmask) < 0)
    {
        perror("sigprocmask error");
    }
 
    fprintf(stdout, "thread|first while. catch sigusr1 or sigusr2 can break\n");
    while(1)
    {
        if(flag_sigusr1 || flag_sigusr2)
        {
            fprintf(stdout, "thread|break\n");
            break;
        }
        sleep(5);
    }
    flag_sigusr1 = 0;
 
    //thread block SIGUSR1
    sigaddset(&newmask, SIGUSR1);
    if(pthread_sigmask(SIG_BLOCK, &newmask, &oldmask) < 0)
    {
        perror("sigprocmask error");
    }
 
    fprintf(stdout, "thread|first while. catch sigusr2 can break\n");
    while(1)
    {
        if(flag_sigusr1 || flag_sigusr2)
        {
            fprintf(stdout, "break\n");
            break;
        }
        sleep(10);
    }
    fprintf(stdout, "thread|thread exit\n");
    return (void *)0;
}
 
int main()
{
    sigset_t    newmask;
    pthread_t  tid;
    int        signo;
 
    //signal action
    signal(SIGUSR1, sig_usr1);
    signal(SIGUSR2, sig_usr2);
    signal(SIGHUP , sig_hup);
 
    if(pthread_create(&tid, NULL, thread_control_signal, NULL) < 0)
    {
        perror("create pthread failed");
        return -1;
    }
 
    //main thread block sigusr1
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGUSR1);
    if(pthread_sigmask(SIG_BLOCK, &newmask, NULL) < 0)
    {
        perror("sigprocmask error");
    }
 
    //main thread wait sighup
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGHUP);
    if(sigwait(&newmask, &signo) < 0)
    {
        perror("sigwait failed");
        return -1;
    }
    fprintf(stdout, "main|get SIGHUP\n");
 
    pthread_kill(tid, SIGUSR2);
    pthread_kill(tid, SIGUSR2);
    pthread_join(tid, NULL);
 
    fprintf(stdout, "main|exit\n");
    return 0;
}

  

kill函数向进程发送信号,pthread_kill用于向线程发送信号。

 

posted @   小 楼 一 夜 听 春 雨  阅读(3455)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2010-01-16 CxImage
2010-01-16 程序员的五种非技术错误 --转载
点击右上角即可分享
微信分享提示