免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5286 | 回复: 9
打印 上一主题 下一主题

请问信号处理中用什么方法代替不可重入的IO操作 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-11-04 17:41 |只看该作者 |倒序浏览
20可用积分
在信号处理中,所有人都提到要使用可重入的函数,去掉不可重入的操作以后程序即正常,但奇怪的是没有人关心程序原来的逻辑怎么办?

我在信号处理中需要进行字符串的格式化,还有写系统日志,但是看起来printf, sprintf, syslog是不能用的,printf虽然无关紧要, 但是我该如何安全地格式化字符串和写日志呢?

sprintf和syslog有什么方法可以替代,或者程序有什么改变可以实现同样的功能吗?
还有在信号处理中调用全局对象的方法也会有总是吗?

谢谢

最佳答案

查看完整内容

我理解所谓reentrant和non reentrant函数的区别就是函数每一次调用时是否完全一致也就是如你列出的第2点所说,当一个函数在执行过程中被中断,并再次被调用,重头开始执行时,其行为是否会发生变化那么如果这个函数中使用了static或者global的变量两次调用的行为很有可能会受其影响而不一样,那么这个函数就是non reentrant的了查了下APUE大概就是这个意思当然,阻塞所有信号应该是可以的因为这就不存在中断处理函数自身被中断的可 ...

论坛徽章:
0
2 [报告]
发表于 2009-11-04 17:41 |只看该作者

回复 #6 danielhf 的帖子

我理解所谓reentrant和non reentrant函数的区别就是函数每一次调用时是否完全一致
也就是如你列出的第2点所说,当一个函数在执行过程中被中断,并再次被调用,重头开始执行时,其行为是否会发生变化
那么如果这个函数中使用了static或者global的变量
两次调用的行为很有可能会受其影响而不一样,那么这个函数就是non reentrant的了
查了下APUE大概就是这个意思

当然,阻塞所有信号应该是可以的
因为这就不存在中断处理函数自身被中断的可能性了,也就无所谓重入了

所以要严格保证信号处理函数的安全的话
至少要保证自己的代码以及调用的库函数都没有使用static/global变量
既然printf族的函数被认为是non reentrant的话
去查看它的代码可能会发现使用到static/global变量的地方

至于调用全局方法,跟调用一个库函数,或者自己定义的函数没有本质区别
关键是看这个方法会不会使用static/global变量,我觉得这是判断是否reentrant的重要依据

ps.
个人觉得没有必要特别在意
完全、严格的reentrant的函数是没有的,因为至少errno变量是大家所共享的

论坛徽章:
0
3 [报告]
发表于 2009-11-04 19:19 |只看该作者

回复 #1 danielhf 的帖子

所谓reentrant和non-reentrant函数并没有十分严格的界定
printf族的函数之所以不是reentrant,我个人猜测大概是因为变长参数的引入
使得函数的实现变得复杂了,其中可能会用到static的或者是global的变量,这就不能重入了
这只是猜测,没有根据

如果实在担心,可以用read/write来读写阿

另外,最后一句话没看懂

论坛徽章:
0
4 [报告]
发表于 2009-11-05 11:20 |只看该作者
谢谢~

你的意思是说没有证据可以说明printf是不可重入的?但我有听说使用printf后程序工作不正常的例子,其实我也不确定,依据APUE中的说法,还是不安全的。

我的问题是希望在信号处理函数中使用sprintf来格式化字串,或者syslog来记录一些信息(假设printf和sprintf有着同样的属性)

在网上找这个问题的时候,都是说把相关的printf去掉,静态变量去掉程序就不出问题了,但是我最想知道的是以前的程序逻辑怎么办?是用什么替代方法实现的?read/write只能代替printf, 但字符串怎么办?

最后一句话是输入法的问题, 调用全局对象方法会怎样? 如下

  1. static Object obj;
  2. bool flag = false;

  3. void signal_handler(int num) {
  4.     obj.func();
  5.     flag = true;
  6. }
复制代码

论坛徽章:
0
5 [报告]
发表于 2009-11-05 12:02 |只看该作者
要将非线程安全的函数改为线程安全的,则只需要修改函数的实现部分。一般通过加入同步机制以保护共享的资源,使之不会被几个进程同时访问。

参考:
http://www.yuanma.org/data/2008/1024/article_3260.htm

你可以使用sprintf向缓冲区中写入,但是要注意缓冲区要加锁。

论坛徽章:
0
6 [报告]
发表于 2009-11-05 18:10 |只看该作者
是不是可以分步来实现,调用写log的函数时只是把内容放到一个链表里,然后发消息给处理函数,处理函数再把内容实际写到缓冲区或者文件什么地方。

论坛徽章:
0
7 [报告]
发表于 2009-11-06 11:46 |只看该作者
原帖由 emmoblin 于 2009-11-5 12:02 发表
要将非线程安全的函数改为线程安全的,则只需要修改函数的实现部分。一般通过加入同步机制以保护共享的资源,使之不会被几个进程同时访问。

参考:
http://www.yuanma.org/data/2008/1024/article_3260.ht ...



1.明显同步机制只能保证线程安全,而不能保证可重入,因为那要修改接口,而我们不可能修改任何接口。
2. 其实真正的问题在于,信号处理程序和产生信号的代码在同一个线程当中,当一个不可重入的函数在执行中途被打断,而信号处理过程中又用到这个函数的情况下会有错误,如果可以保证在使用不可重入的函数时不产生任何信号,也许就没事了?
3. 我读了sysvinit的代码,它在调用syslog的时候block了所有的信号,也许这是一个办法么?没有验证过

论坛徽章:
11
技术图书徽章
日期:2014-03-01 14:44:34天蝎座
日期:2014-05-21 22:11:59金牛座
日期:2014-05-30 17:06:14
8 [报告]
发表于 2009-11-08 02:06 |只看该作者
格式化字符串是调用者提供的buffer,只要buffer在栈上分配,sprintf是可以重入的。标准IO里有大把的不可重入函数,包括printf,主要是全局变量,静态变量以及为了线程安全而设置的锁引起,用系统调用write代替即可。

论坛徽章:
0
9 [报告]
发表于 2009-11-09 12:33 |只看该作者
这个分数怎么分配,我不会,也没有什么按钮或者链接,怎么给分呐?

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
10 [报告]
发表于 2009-11-14 11:18 |只看该作者
原帖由 danielhf 于 2009-11-9 12:33 发表
这个分数怎么分配,我不会,也没有什么按钮或者链接,怎么给分呐?

悬赏分只能给一个人。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP