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用于向线程发送信号。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· 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 程序员的五种非技术错误 --转载