linux线程关闭信号,Linux/UNIX用同步方法处理异步信号
Linux/UNIX进程信号处理复杂易出错,而用在多线程中就更加复杂脆弱,这里不探讨相关历史渊源,只给出一种在实践中简单可靠的信号处理方式。后文讨论的线程模型是POSIX thread(pth
一. 前言 Linux/UNIX进程信号处理复杂易出错,而用在多线程中就更加复杂脆弱,这里不探讨相关历史渊源,只给出一种在实践中简单可靠的信号处理方式。后文讨论的线程模型是POSIX thread(pthread),Linux和主流UNIX均支持pthread。 二. 进程与线程信号模型 这里假设读者已熟悉进程信号模型,下面列出多线程环境中,信号模型的进一步细节: 1.信号action属于进程级别。忽略信号action / 默认action(可能core dump) / 自定义action,所有线程共享该action。 2.信号递交到进程时,内核会任选一个线程来处理,只有下面三种情况才会由特定线程处理:信号源于线程执行了特定硬件指令,如SIGBUS / SIGFPE / SIGILL / SIGSEGV。线程写一个关闭读端或出错的流式管道,触发SIGPIPE,常见于pipe / FIFO / UNIX domain socket / TCP socket。pthread_kill和pthread_sigqueue所发出信号。 3.信号mask属于线程级别,可以通过pthread_sigmask来控制。 4.信号pending属于线程级别unix线程切换,可由sigpending获取。 三. 可重入(re-entrant)函数 / 线程安全(thread-safe)函数 / 异步信号安全(async-signal-safe)函数 SUS有很长的列表规定了哪些不是线程安全函数,哪些是异步信号安全函数,但没必要记那个表格,只要对分类原理有深入理解,必要时才查标准或手册。下面列出一些关键点: 1.可重入是一个理论概念,可以理解为给定的输入能得到确定性输出,不能是随机或undefined行为,实践中需要有上下文环境。在异步信号执行中,可重入意味着异步信号安全。在多线程执行中,可重入意味着线程安全。 2.异步信号安全,同一个线程或不同线程,同步执行或异步执行,都能保证安全性。这在系统调用和库函数中属于少数派,所以SUS详细列出了这些函数。IO系统调用open/close/read/write属于此类;标准IO函数fopen / fclose / fread / fwrite / printf等等则不属于此类。一般修改共享数据结构意味着异步信号不安全,比如标准IO函数;不过有例外,存取sig_atomic_t,gcc支持的硬件架构中存取1/2/4/8字节的整数类型,更广义的就是最新C/C++标准支持的atomic系列函数,这些都是异步信号安全的。 3.线程安全,可供多个线程安全调用的函数,包括异步信号安全函数。这个门槛不高,多数系统调用和库函数都满足,所以SUS只规定了哪些函数不必是线程安全的。标准IO函数属于此类,malloc / free也是,它们虽然使用了全局数据结构,但是内部有互斥锁,可以保证安全性,localtime则不是,它用了静态数据结构,内部没有锁保护,标准有localtime_r替代,’xxx_r’是一大类线程安全的函数,具体可以查文档。修改共享数据结构却没有锁保护,意味着线程不安全。 四.运行环境 Linux: kernel 3.12 / gcc 4.8 UNIX: mac os x 10.9 / llvm 3.4 五. 一个常见的错误 很多人在信号处理函数中经常写一堆printf,几十行的demo还行,但实际项目中就是一个风险,可能出错的终将出错,往往关键时刻掉链子。下面就构造一个稍极端的例子演示会发生什么。 C源码: 点击(此处)折叠或打开 #include #include "lgr_hdr.h" static void handler(int sig) { printf("this is handler\n"); } int main(int argc, char **argv) { struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = handler; if (sigaction(SIGUSR1, &sa, NULL) == -1) err_sys("sigaction"); while (1) { printf("this is main\n"); } return 0; } 构造错误场景的步骤: 1. 启动C程序。 bash-4.2 $./async_signal | grep -F handler 2. 用Python解释器每隔10毫秒,向C程序发送一个SIGUSR1,直到C程序停止输出内容。 bash-4.2 $ps -ef|grep async lgr 1108 945 99 17:37 pts/0 00:00:25 ./async_signal bash-4.2 $python Python 2.7.5 (default, Feb 19 2014, 13:47:40) [GCC 4.8.2 20131212 (Red Hat 4.8.2-7)] on linux2 (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |