热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

100多线程与信号

不知道你是否还记得之前在进程中的信号处理时,提到过阻塞信号集与未决信号集的概念,如果你已经忘记了,请参考《阻塞信号与未决信号》一文回忆一下

不知道你是否还记得之前在进程中的信号处理时,提到过阻塞信号集未决信号集的概念,如果你已经忘记了,请参考《阻塞信号与未决信号》一文回忆一下。


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 参数

表示你指定的信号集合


  • oldset

返回旧的阻塞信号集


  • 返回值 int

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 代码

// th_sig.c
#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;);elseputchar(&#39;0&#39;);}puts("");
}// fun1 线程
void* fun1(void* arg) {// 阻塞 SIGINT 信号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);}
}// fun2 线程
void* fun2(void* arg) {sigset_t st; while(1) {printf("I&#39;m fun2:\t");sigpending(&st);printsigset(&st);sleep(3);}
}int main() {// 创建线程前阻塞 SIGQUITsigset_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 发送信号给所有线程

推荐阅读
  • 在iOS开发中,多线程技术的应用非常广泛,能够高效地执行多个调度任务。本文将重点介绍GCD(Grand Central Dispatch)在多线程开发中的应用,包括其函数和队列的实现细节。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 深入理解Java多线程并发处理:基础与实践
    本文探讨了Java中的多线程并发处理机制,从基本概念到实际应用,帮助读者全面理解并掌握多线程编程技巧。通过实例解析和理论阐述,确保初学者也能轻松入门。 ... [详细]
  • 本文详细介绍了Linux系统中信号量的相关函数,包括sem_init、sem_wait、sem_post和sem_destroy,解释了它们的功能和使用方法,并提供了示例代码。 ... [详细]
  • RTThread线程间通信
    线程中通信在裸机编程中,经常会使用全局变量进行功能间的通信,如某些功能可能由于一些操作而改变全局变量的值,另一个功能对此全局变量进行读取& ... [详细]
  • C语言编写线程池的简单实现方法
    2019独角兽企业重金招聘Python工程师标准好文章,一起分享——有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带 ... [详细]
  • 在 Linux 环境下,多线程编程是实现高效并发处理的重要技术。本文通过具体的实战案例,详细分析了多线程编程的关键技术和常见问题。文章首先介绍了多线程的基本概念和创建方法,然后通过实例代码展示了如何使用 pthreads 库进行线程同步和通信。此外,还探讨了多线程程序中的性能优化技巧和调试方法,为开发者提供了宝贵的实践经验。 ... [详细]
  • 本文详细探讨了Zebra路由软件中的线程机制及其实际应用。通过对Zebra线程模型的深入分析,揭示了其在高效处理网络路由任务中的关键作用。文章还介绍了线程同步与通信机制,以及如何通过优化线程管理提升系统性能。此外,结合具体应用场景,展示了Zebra线程机制在复杂网络环境下的优势和灵活性。 ... [详细]
  • 本文总结了Java程序设计第一周的学习内容,涵盖语言基础、编译解释过程及基本数据类型等核心知识点。 ... [详细]
  • 本次考试于2016年10月25日上午7:50至11:15举行,主要涉及数学专题,特别是斐波那契数列的性质及其在编程中的应用。本文将详细解析考试中的题目,并提供解题思路和代码实现。 ... [详细]
  • 本文介绍了一种解决二元可满足性(2-SAT)问题的方法。通过具体实例,详细解释了如何构建模型、应用算法,并提供了编程实现的细节和优化建议。 ... [详细]
  • 单例模式是软件开发中常用的设计模式之一,用于确保一个类只有一个实例,并提供一个全局访问点。本文探讨了在单例模式实现中使用volatile关键字的重要性,特别是在懒汉模式下的应用。 ... [详细]
  • 在MFC框架中,存在多个全局函数,用于在不同对象间获取信息或创建新对象。其中,`afxGetApp`函数尤为关键,它能够帮助开发者轻松获取当前应用程序的实例指针。本文将详细解析`afxGetApp`函数的内部机制及其在MFC应用程序中的具体应用场景,探讨其在提升代码可维护性和灵活性方面的优势。此外,还将介绍其他常用全局函数如`AfxWinInit()`和`AfxBeginThread()`的功能和使用方法,为开发者提供全面的参考。 ... [详细]
  • 本文深入探讨了IO复用技术的原理与实现,重点分析了其在解决C10K问题中的关键作用。IO复用技术允许单个进程同时管理多个IO对象,如文件、套接字和管道等,通过系统调用如`select`、`poll`和`epoll`,高效地处理大量并发连接。文章详细介绍了这些技术的工作机制,并结合实际案例,展示了它们在高并发场景下的应用效果。 ... [详细]
author-avatar
筱庆儿宝贝
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有