电子文档交易市场
安卓APP | ios版本
电子文档交易市场
安卓APP | ios版本
换一换
首页 金锄头文库 > 资源分类 > DOCX文档下载
分享到微信 分享到微博 分享到QQ空间

Linux多线程应用中如何编写安全的信号处理函数

  • 资源ID:469786278       资源大小:42.15KB        全文页数:13页
  • 资源格式: DOCX        下载积分:15金贝
快捷下载 游客一键下载
账号登录下载
微信登录下载
三方登录下载: 微信开放平台登录   支付宝登录   QQ登录  
二维码
微信扫一扫登录
下载资源需要15金贝
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
如填写123,账号就是123,密码也是123。
支付方式: 支付宝    微信支付   
验证码:   换一换

 
账号:
密码:
验证码:   换一换
  忘记密码?
    
1、金锄头文库是“C2C”交易模式,即卖家上传的文档直接由买家下载,本站只是中间服务平台,本站所有文档下载所得的收益全部归上传人(卖家)所有,作为网络服务商,若您的权利被侵害请及时联系右侧客服;
2、如你看到网页展示的文档有jinchutou.com水印,是因预览和防盗链等技术需要对部份页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有jinchutou.com水印标识,下载后原文更清晰;
3、所有的PPT和DOC文档都被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;下载前须认真查看,确认无误后再购买;
4、文档大部份都是可以预览的,金锄头文库作为内容存储提供商,无法对各卖家所售文档的真实性、完整性、准确性以及专业性等问题提供审核和保证,请慎重购买;
5、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据;
6、如果您还有什么不清楚的或需要我们协助,可以点击右侧栏的客服。
下载须知 | 常见问题汇总

Linux多线程应用中如何编写安全的信号处理函数

Linux多线程应用中如何编写安全的信号处理函数Linux 多线程应用中如何编写安全的信号处理函数 简介: 关于代码的可重入性,设计开发人员一般只考虑到线程安全,异步信号处理函数的安全却往往被忽略。本文首先介绍如何编写安全的异步信号处理函数;然后举例说明在多线程应用中如何构建模型让异步信号在指定的线程中以同步的方式处理。 Linux 多线程应用中编写安全的信号处理函数 在开发多线程应用时,开发人员一般都会考虑线程安全,会使用 pthread_mutex 去保护全局变量。如果应用中使用了信号,而且信号的产生不是因为程序运行出错,而是程序逻辑需要,譬如 SIGUSR1、SIGRTMIN 等,信号在被处理后应用程序还将正常运行。在编写这类信号处理函数时,应用层面的开发人员却往往忽略了信号处理函数执行的上下文背景,没有考虑编写安全的信号处理函数的一些规则。本文首先介绍编写信号处理函数时需要考虑的一些规则;然后举例说明在多线程应用中如何构建模型让因为程序逻辑需要而产生的异步信号在指定的线程中以同步的方式处理。 回页首 线程和信号 Linux 多线程应用中,每个线程可以通过调用 pthread_sigmask 设置本线程的信号掩码。一般情况下,被阻塞的信号将不能中断此线程的执行,除非此信号的产生是因为程序运行出错如 SIGSEGV;另外不能被忽略处理的信号 SIGKILL 和 SIGSTOP 也无法被阻塞。 当一个线程调用 pthread_create 创建新的线程时,此线程的信号掩码会被新创建的线程继承。 POSIX.1 标准定义了一系列线程函数的接口,即 POSIX threads(Pthreads)。Linux C 库提供了两种关于线程的实现:LinuxThreads和 NPTL(Native POSIX Threads Library)。LinuxThreads已经过时,一些函数的实现不遵循POSIX.1 规范。NPTL 依赖 Linux 2.6 内核,更加遵循 POSIX.1 规范,但也不是完全遵循。 基于 NPTL 的线程库,多线程应用中的每个线程有自己独特的线程 ID,并共享同一个进程ID。应用程序可以通过调用kill(getpid,signo) 将信号发送到进程,如果进程中当前正在执行的线程没有阻碍此信号,则会被中断,线号处理函数会在此线程的上下文背景中执行。应用程序也可以通过调用 pthread_kill(pthread_t thread, int sig) 将信号发送给指定的线程,则线号处理函数会在此指定线程的上下文背景中执行。 基于LinuxThreads的线程库,多线程应用中的每个线程拥有自己独特的进程 ID,getpid 在不同的线程中调用会返回不同的值,所以无法通过调用 kill(getpid,signo) 将信号发送到整个进程。 下文介绍的在指定的线程中以同步的方式处理异步信号是基于使用了 NPTL 的 Linux C 库。请参考“Linux 线程模型的比较:LinuxThreads 和 NPTL”和“pthreads(7) - Linux man page”进一步了解 Linux 的线程模型,以及不同版本的 Linux C 库对 NPTL 的支持。 回页首 编写安全的异步信号处理函数 信号的产生可以是: · 用户从控制终端终止程序运行,如Ctrk + C 产生 SIGINT; · 程序运行出错时由硬件产生信号,如访问非法地址产生 SIGSEGV; · 程序运行逻辑需要,如调用 kill、raise 产生信号。 因为信号是异步事件,即信号处理函数执行的上下文背景是不确定的,譬如一个线程在调用某个库函数时可能会被信号中断,库函数提前出错返回,转而去执行信号处理函数。对于上述第三种信号的产生,信号在产生、处理后,应用程序不会终止,还是会继续正常运行,在编写此类信号处理函数时尤其需要小心,以免破坏应用程序的正常运行。关于编写安全的信号处理函数主要有以下一些规则: · 信号处理函数尽量只执行简单的操作,譬如只是设置一个外部变量,其它复杂的操作留在信号处理函数之外执行; · errno 是线程安全,即每个线程有自己的 errno,但不是异步信号安全。如果信号处理函数比较复杂,且调用了可能会改变errno 值的库函数,必须考虑在信号处理函数开始时保存、结束的时候恢复被中断线程的 errno 值; · 信号处理函数只能调用可以重入的 C 库函数;譬如不能调用 malloc,free以及标准 I/O 库函数等; · 信号处理函数如果需要访问全局变量,在定义此全局变量时须将其声明为 volatile,以避免编译器不恰当的优化。 从整个 Linux 应用的角度出发,因为应用中使用了异步信号,程序中一些库函数在调用时可能被异步信号中断,此时必须根据errno的值考虑这些库函数调用被信号中断后的出错恢复处理,譬如socket 编程中的读操作: rlen = recv(sock_fd, buf, len, MSG_WAITALL); if (rlen = -1) && (errno = EINTR) / this kind of error is recoverable, we can set the offset change /rlen as 0 and continue to recv 回页首 在指定的线程中以同步的方式处理异步信号 如上文所述,不仅编写安全的异步信号处理函数本身有很多的规则束缚;应用中其它地方在调用可被信号中断的库函数时还需考虑被中断后的出错恢复处理。这让程序的编写变得复杂,幸运的是,POSIX.1 规范定义了sigwait、sigwaitinfo 和pthread_sigmask 等接口,可以实现: · · 以同步的方式处理异步信号; 在指定的线程中处理信号。 这种在指定的线程中以同步方式处理信号的模型可以避免因为处理异步信号而给程序运行带来的不确定性和潜在危险。 sigwait sigwait 提供了一种等待信号的到来,以串行的方式从信号队列中取出信号进行处理的机制。sigwait只等待函数参数中指定的信号集,即如果新产生的信号不在指定的信号集内,则 sigwait继续等待。对于一个稳定可靠的程序,我们一般会有一些疑问: 多个相同的信号可不可以在信号队列中排队? · 如果信号队列中有多个信号在等待,在信号处理时有没有优先级规则? · 实时信号和非实时信号在处理时有没有什么区别? 笔者写了一小段测试程序来测试 sigwait 在信号处理时的一些规则。 · 清单 1. sigwait_test.c #include <signal.h> #include <errno.h> #include <pthread.h> #include <unistd.h> #include <sys/types.h> void sig_handler(intsignum) printf("Receive signal. %dn", signum); void* sigmgr_thread sigset_twaitset, oset; int sig; intrc; pthread_tppid = pthread_self; pthread_detach(ppid); sigemptyset(&waitset); sigaddset(&waitset, SIGRTMIN); sigaddset(&waitset, SIGRTMIN+2); sigaddset(&waitset, SIGRTMAX); sigaddset(&waitset, SIGUSR1); sigaddset(&waitset, SIGUSR2); while (1) rc = sigwait(&waitset, &sig); if (rc != -1) sig_handler(sig); else printf("sigwaitinfo returned err: %d; %sn", errno, strerror(errno); int main sigset_tbset, oset; int i; pid_tpid = getpid; pthread_tppid; sigemptyset(&bset); sigaddset(&bset, SIGRTMIN); sigaddset(&bset, SIGRTMIN+2); sigaddset(&bset, SIGRTMAX); sigaddset(&bset, SIGUSR1); sigaddset(&bset, SIGUSR2); if (pthread_sigmask(SIG_BLOCK, &bset, &oset) != 0) printf("! Set pthread mask failedn"); kill(pid, SIGRTMAX); kill(pid, SIGRTMAX); kill(pid, SIGRTMIN+2); kill(pid, SIGRTMIN); kill(pid, SIGRTMIN+2); kill(pid, SIGRTMIN); kill(pid, SIGUSR2); kill(pid, SIGUSR2); kill(pid, SIGUSR1); kill(pid, SIGUSR1); / Create the dedicated thread sigmgr_thread which will handle signals synchronously pthread_create(&ppid, NULL, sigmgr_thread, NULL); sleep(10); exit (0); 程序编译运行在 RHEL4 的结果如下: 图 1. sigwait测试程序执行结果 从以上测试程序发现以下规则: · 对于非实时信号,相同信号不能在信号队列中排队;对于实时信号,相同信号可以在信号队列中排队。 · 如果信号队列中有多个实时以及非实时信号排队,实时信号并不会先于非实时信号被取出,信号数字小的会先被取出:如 SIGUSR1会先于 SIGUSR2 (12),SIGRTMIN会先于 SIGRTMAX (64),非实时信号因为其信号数字小而先于实时信号被取出。 sigwaitinfo 以及 sigtimedwait 也提供了与 sigwait 函数相似的功能。 Linux 多线程应用中的信号处理模型 在基于 Linux 的多线程应用中,对于因为程序逻辑需要而产生的信号,可考虑调用 sigwait使用同步模型进行处理。其程序流程如下: 1. 主线程设置信号掩码,阻碍希望同步处理的信号;主线程的信号掩码会被其创建的线程继承; 2. 主线程创建信号处理线程;信号处理线程将希望同步处理的信号集设为 sigwait的第一个参数。 3. 主线程创建工作线程。 图 2. 在指定的线程中以同步方式处理异步信号的模型 代码示例 以下为一个完整的在指定的线程中以同步的方式处理异步信号的程序。 主线程设置信号掩码阻碍 SIGUSR1 和 SIGRTMIN 两个信号,

注意事项

本文(Linux多线程应用中如何编写安全的信号处理函数)为本站会员(博****1)主动上传,金锄头文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即阅读金锄头文库的“版权提示”【网址:https://www.jinchutou.com/h-59.html】,按提示上传提交保证函及证明材料,经审查核实后我们立即给予删除!

温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




关于金锄头网 - 版权申诉 - 免责声明 - 诚邀英才 - 联系我们
手机版 | 川公网安备 51140202000112号 | 经营许可证(蜀ICP备13022795号)
©2008-2016 by Sichuan Goldhoe Inc. All Rights Reserved.