作者:筱庆儿宝贝 | 来源:互联网 | 2023-10-15 07:20
不知道你是否还记得之前在进程中的信号处理时,提到过阻塞信号集 与未决信号集 的概念,如果你已经忘记了,请参考《阻塞信号与未决信号》一文回忆一下。
1. 多线程程序中的信号 在多线程中,每一个线程都有属于自己的阻塞信号集与未决信号集。当一个线程派生另一个线程的时候,会继承父线程的阻塞信号集,但是不会继承未决信号集,并且新线程会清空未决信号集。
2. 相关函数 2.1 设置阻塞信号集的函数 在多线程程序中,如果要设置线程的阻塞信号集,不能再使用 sigprocmask 函数,而应该使用 pthread_sigmask,其定义如下:
int pthread_sigmask(int how, const sigset_t *set , sigset_t *oldset);
这个函数的用法和 sigprocmask 是一样的。
how 参数
SIG_BLOCK 该选项表示将 set 参数指示的信号集中的信号添加到进程阻塞集中 SIG_UNBLOCK 该选项与功能 SIG_BLOCK 相反,表示将线程阻塞信号集中指定的信号删除 SIG_SETMASK 该选项表示将线程阻塞信号集直接设定为你指定的 set set 参数
表示你指定的信号集合
返回旧的阻塞信号集
0 表示成功,-1 失败。
2.2 获取未决信号的函数 该函数仍然是 sigpending,没有变化。它的原型如下:
int sigpending(sigset_t *set );
2.3 信号发送函数 kill 函数只能给指定的进程发送函数,而是使用 pthread_kill 可以给指定的线程发送函数。它的原型如下:
int pthread_kill(pthread_t thread, int sig );
3. 实验 程序 th_sig 做了下面几个工作:
在主线程阻塞了 SIGQUIT 信号 在 fun1 线程中阻塞了 SIGINT 信号 在 fun2 线程中什么也没阻塞 3.1 代码 #include #include #include #include void printsigset(const sigset_t *set ) {int i;for (i &#61; 1 ; i <&#61; 64 ; i&#43;&#43;) {if (i&#61;&#61;33 ) putchar (&#39; &#39; );if (sigismember(set , i) &#61;&#61; 1 )putchar (&#39;1&#39; );else putchar (&#39;0&#39; );}puts ("" ); }void * fun1(void * arg) {sigset_t mask, st; sigemptyset(&mask);sigaddset(&mask, SIGINT);pthread_sigmask(SIG_BLOCK, &mask, NULL);while (1 ) {printf ("I&#39;m fun1:\t" );sigpending(&st);printsigset(&st);sleep(3 );} }void * fun2(void * arg) {sigset_t st; while (1 ) {printf ("I&#39;m fun2:\t" );sigpending(&st);printsigset(&st);sleep(3 );} }int main() {sigset_t mask, st; sigemptyset(&mask);sigaddset(&mask, SIGQUIT);pthread_sigmask(SIG_BLOCK, &mask, NULL);pthread_t tid1, tid2;pthread_create(&tid1, NULL, fun1, NULL);pthread_create(&tid2, NULL, fun2, NULL);sleep(2 );pthread_kill(tid1, SIGINT);while (1 ) {printf ("I&#39;m main:\t" );sigpending(&st);printsigset(&st);sleep(3 );}return 0 ; }
3.2 编译与运行 $ gcc th_sig. c -o th_sig -lpthread
图1 运行结果
关于图 1 的说明&#xff1a;左侧是线程的名字&#xff0c;右侧是打印的未决队列&#xff0c;也就是未被信号处理函数处理的信号。其中第 1 列是 SIGHUP 信号&#xff0c;第 2 列表示 SIGINT 信号&#xff0c;第 3 列表示 SIGQUIT 信号。
当主线程休眠 2 秒后&#xff0c;给线程 fun1 发送了一个 SIGINT 信号&#xff0c;此时 fun1 的未决信号集中第 2 列变成了 1 &#xff08;图 1 上的第 5 行&#xff09;。
在后面某个时候&#xff0c;按下了 CTRL &#43; \&#xff0c;表示发送信号 SIGQUIT 给前台进程组中的进程。接下来&#xff0c;可以发现&#xff0c;所有的线程未决信号集中的第 3 列都变成了 1. 这说明了两件事&#xff1a;
线程继承了父线程阻塞信号集 kill 信号会发送给进程中的所有线程 4. 总结 每个线程有自己的阻塞信号集与未决信号集 线程会继承父线程的阻塞信号集&#xff0c;新线程会清空未决信号集 pthread_kill 发送信号给指定线程 kill 发送信号给所有线程