linux 多线程之间信号传递
函数
sigwait
sigwait的含义就如同它的字面意思:等待某个信号的到来。如果调用该函数的线程没有等到它想等待的信号那么该线程就休眠。要达到等到一个信号,我们得做下面的事:
首先,定义一个信号集:
#include <signal.h>
sigset_t set;
其次,向信号集中加入我们想等待的信号:
#include <signal.h>
int sigemptyset(sigset_t *set);//清空信号集
int sigaddset(sigset_t *set,int signo);//将某个信号加入到信号集中
int sigdelset(sigset_t *set,int signo);//删除信号集中的某个信号
int sigfillset(sigset_t *set);//包含所有已定义的信号
最后,将该信号集中的信号加入到线程信号屏蔽字(线程信号等待队列)中:
#include <signal.h>
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
how:
SIG_BLOCK:把参数set中的信号添加到线程的信号屏蔽字中
SIG_SETMASK:把线程的信号屏蔽字设置为参数set中的信号
SIG_UNBLOCK:从线程信号屏蔽字中删除参数set中的信号
set:用户设置的信号屏蔽字
oldset:返回原先的信号屏蔽字
经过这样的设置我们就可以在线程该等待的地方调用sigwait休眠该线程了。
pthread_kill
#include <signal.h>
int pthread_kill(pthread_t thread, int sig);
thread:给哪个线程发送信号
sig:发送的信号值
sigaction
sigaction函数可以读取和修改与指定信号相关联的处理动作,它的声明如下:
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
参数:
--第一个参数是信号的值,可以为除了SIGKILL及SIGSTOP外的任何一个特定有效的信号(因为这两个信号定义了自己的处理函数,将导致信号安装错误)。
SIG_DFL,SIG_IGN 分别表示无返回值的函数指针,指针值分别是0和1,这两个指针值逻辑上讲是实际程序中不可能出现的函数地址值。
SIG_DFL:默认信号处理程序。
SIG_IGN:忽略信号的处理程序。
--第二个参数是指向sigaction的一个实例的指针,在sigaction的实例中,指定了对特定信号的处理,可以为NULL,进程会以缺省方式对信号处理。
--第三个参数oldact指向的对象用来保存原来对相应信号的处理,可以为NULL。
返回值:
函数成功返回0,失败返回-1。
sigaction函数检查或修改与指定信号相关联的处理动作,该函数取代了signal函数。因为signal函数在信号未决时接收信号可能出现问题,所以使用sigaction更安全。
sigaction结构体:
struct sigaction
{
void (*sa_handler)(int);//信号处理程序 不接受额外数据
void (*sa_sigaction)(int, siginfo_t *, void *);//信号处理程序,能接受额外数据,可以和sigqueue配合使用
sigset_t sa_mask;
int sa_flags;//影响信号的行为SA_SIGINFO表示能接受数据
void (*sa_restorer)(void);//废弃
};
sa_handler & sa_sigaction
信号处理函数的指针,二者用其一:如果sa_flags中存在SA_SIGINFO标志,那么sa_sigaction将作为signum信号的处理函数,否则用sa_handler。
sa_mask
指定一个系统在处理该信号时要屏蔽(阻塞)的信号集合,即在调用该信号捕捉函数之前,这一信号集要加进进程的信号屏蔽字中。
仅当从信号捕捉函数返回时再将进程的信号屏蔽字复位为原先值。
另外,除了SA_NODEFER标志被指定外,触发信号处理函数执行的那个信号也会被阻塞。
sa_flag
指定一系列用于修改信号处理过程行为的标志,由下面的0个或多个标志通过or运算组合而成:
SA_SIGINFO 指定信号处理函数需要三个参数,所以应使用sa_sigaction替代sa_handler。
SA_NODEFER 在信号处理函数处置信号的时段中,核心程序不会把这个间隙中产生的信号阻塞。
SA_INTERRUPT 由此信号中断的系统调用不会自动重启
SA_RESTART 核心会自动重启信号中断的系统调用,否则返回EINTR错误值。(重启被中断的系统调用)
SA_RESETHAND 信号处理函数接收到信号后,会先将对信号处理的方式设为预设方式,而且当函数处理该信号时,后来发生的信号将不会被阻塞。
SA_ONSTACK 如果利用sigaltstack()建立信号专用堆栈,则此标志会把所有信号送往该堆栈。
SA_NOCLDSTOP 假如signum的值是SIGCHLD,则在子进程停止或恢复执行时不会传信号给调用本系统调用的进程。
SA_NOCLDWAIT 当调用此系统调用的进程之子进程终止时,系统不会建立zombie进程。
程序示例
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
void *threadfunc1(void *pvoid)
{
int signum;
sigset_t sig;
sigemptyset(&sig);
sigaddset(&sig,SIGUSR1);
pthread_sigmask(SIG_BLOCK,&sig,NULL);//设置该线程的信号屏蔽字为SIGUSR1
while(1)
{
sigwait(&sig,&signum);//睡眠等待SIGUSR1信号的到来
printf("threadfunc1 waiting is over!\n");
}
}
void *threadfunc2(void *pvoid)
{
int signum;
sigset_t sig;
sigemptyset(&sig);
sigaddset(&sig,SIGUSR1);
pthread_sigmask(SIG_BLOCK,&sig,NULL);//设置该线程的信号屏蔽字为SIGUSR1
while(1)
{
sigwait(&sig,&signum);//睡眠等待SIGUSR1信号的到来
printf("threadfunc2 waiting is over!\n");
}
}
void main()
{
pthread_t thread1,thread2;
pthread_create(&thread1,NULL,threadfunc1,(void *)NULL);
pthread_create(&thread2,NULL,threadfunc2,(void *)NULL);
pthread_detach(thread1);
pthread_detach(thread2);
struct sigaction act;
act.sa_handler=SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
sigaction(SIGUSR1,&act,0);//设置信号SIGUSR1的处理方式忽略
while(1)
{
int i;
printf("please input select a number in (1,2)!\n");
scanf("%d",&i);
if(i==1)
pthread_kill(thread1,SIGUSR1);
if(i==2)
pthread_kill(thread2,SIGUSR1);
}
}
编译:
gcc -o pthread pthread.c -lpthread

自定义信号
用户自定义的信号不是只有SIGUSR1,SIGUSR2,linux下预留了__SIGRTMIN(32)到__SIGRTMAX(64)可供用户自定义,当用户需要自定义信号时可以采用下面的方法:
#define SIG_RECVDATA __SIGRTMIN+offsetnum
offset是一个偏移量,实时信号前三个最好不要用,linux thread在使用它们。
例如使用:
#define SIG_RECVDATA __SIGRTMIN+10
linux 多线程之间信号传递的更多相关文章
- Linux 多线程应用中如何编写安全的信号处理函数
http://blog.163.com/he_junwei/blog/static/1979376462014021105242552/ http://www.ibm.com/developerwor ...
- Linux 多线程应用中如何编写安全的信号处理函数【转】
转自:https://www.cnblogs.com/virusolf/p/4945642.html http://blog.163.com/he_junwei/blog/static/1979376 ...
- 《Linux多线程服务端编程:使用muduo C++网络库》上市半年重印两次,总印数达到了9000册
<Linux多线程服务端编程:使用muduo C++网络库>这本书自今年一月上市以来,半年之内已经重印两次(加上首印,一共是三次印刷),总印数达到了9000册,这在技术书里已经算是相当不错 ...
- [转]一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程
一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程 希望此文能给初学多线程编程的朋友带来帮助,也希望牛人多多指出错误. 另外感谢以下链接的作者给予,给我的学习带来了很大帮助 http ...
- LINUX多线程(一)(创建和退出)
1. Linux多线程概述 1.1. 概述 进程是系统中程序执行和资源分配的基本单位.每个进程有自己的数据段.代码段和堆栈段.这就造成进程在进行切换等操作时都需要有比较负责的上下文切换等动作.为了进一 ...
- Linux多线程编程和Linux 2.6下的NPTL
Linux多线程编程和Linux 2.6下的NPTL 在Linux 上,从内核角度而言,基本没有什么线程和进程的区别--大家都是进程.一个进程的多个线程只是多个特殊的进程他们虽然有各自的进程描述结构, ...
- Linux多线程——使用互斥量同步线程
前文再续,书接上一回,在上一篇文章: Linux多线程——使用信号量同步线程中,我们留下了一个如何使用互斥量来进行线程同步的问题,本文将会给出互斥量的详细解说,并用一个互斥量解决上一篇文章中,要使用两 ...
- Linux多线程编程小结
Linux多线程编程小结 前一段时间由于开题的事情一直耽搁了我搞Linux的进度,搞的我之前学的东西都遗忘了,非常烦躁的说,如今抽个时间把之前所学的做个小节.文章内容主要总结于<Linux程序 ...
- 笔记整理--Linux多线程
Unix高级环境编程系列笔记 (2013/11/17 14:26:38) Unix高级环境编程系列笔记 出处信息 通过这篇文字,您将能够解答如下问题: 如何来标识一个线程? 如何创建一个新线程? 如何 ...
随机推荐
- 简单拼接图像的tile_images和tile_images_offset算子
有时候通常需要简单的拼图,不涉及图像融合之类的,仅仅是简单的平移将多张图拼接成一张图.tile_images和tile_images_offset就是用于简单拼图的2个算子. 谈到拼图,肯定有以下问题 ...
- php判断一个数组是另一个数组的子集
需求最少的时间复杂度判断$a数组是否是$b数组的子集 // 快速的判断$a数组是否是$b数组的子集$a = array(135,138);$b = array(135,138,137); 实现方法 这 ...
- Zookeeper 目录
Zookeeper 目录 Zookeeper 致力于提供一个高性能.高可用,且具有严格的顺序访问控制能力(主要是写操作的严格顺序性)的分布式协调服务.以下是我整理的笔记. 一.分布式理论基础 1.1 ...
- 现在有很多第三方的SDK来做直播,那么我们改选择哪一种?
现在大部分的都会借助第三方的直播技术,这样可以保证直播的质量,趣拍直播就很不错,SDK很好集成,芒果直播也在用.下面来分析一下趣拍直播的一些心得. 如何快速搭建一个完整的手机直播系统 在这个直播如火如 ...
- 20155316 2016-2017-2 《Java程序设计》第6周学习总结
教材学习内容总结 IO操作的目标 从数据源当中读取数据,以及将数据写入到数据目的地当中: I/O的来源地与目的地多种多样 I/O的流向:输入流.输出流.参照物 IO的分类方法 输入流\输出流: 字节流 ...
- redis 工具
搜索关键词:redis 工具 推荐:http://redisdesktop.com/download 点评:使用顺手,顺畅. ★★★★★ 五星好评 备注:redis key 可以采用某种format ...
- Windows与Linux相互远程桌面连接
对于远程桌面连接Linux,大家可能会第一时间想到使用VNC,,远程桌面Windows,大家第一时间会想到使用Windows自带的远程桌面.那么有没有办法,使得在Linux中可以远程Windo ...
- java并发编程实战:第十五章----原子变量与非阻塞机制
非阻塞算法:使用底层的原子机器指令(例如比较并交换指令)代替锁来确保数据在并发访问中的一致性 应用于在操作系统和JVM中实现线程 / 进程调度机制.垃圾回收机制以及锁和其他并发数据结构 可伸缩性和活跃 ...
- 使用VMWare12.0安装Ubuntu系统
使用VMWare12.0安装Ubuntu系统 Vmware12的虚拟机的文档说明: http://pubs.vmware.com/workstation-12/index.jsp#com.vmware ...
- (2)-生成JSONObject的方法
生成JSONObject一般有两种方式,通过javabean或者map类型来生成.如下面的例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2 ...