linux下使用多线程的fork和system会出现问题

来源:互联网 发布:东大网络教育 编辑:程序博客网 时间:2024/05/17 05:08

根据我的经验,linux下使用pthread库写多线程程序时,在调用系统调用/库函数方面,应注意至少如下几点:

1、创建了线程后,不要再使用fork()/vfork()创建子进程

2、尽量不使用signal机制

3、...

 

关于1,有个具体的教训。我实现了一个动态库,该库的功能在一个独立线程里运行。同事A实现了另一个动态库,库的功能在也一个独立线程里运行。这两个库需要访问一设备,该设备只支持一个使用者访问,因此有个全局的信号量,来保证这两个线程能交替的访问该设备。我们的测试代码表明这两个库可以正常的配合工作。然后这两个库被交给同事B,集成到他的应用程序里。问题出现了,只要我和A的线程同时运行,几乎必然出现同时访问设备的错误情况,似乎用来保护的信号量失败了。多次检查库的代码,没有发现问题。偶然间,发现同事B的代码调用了system(),把system()调用替换成相应的代码实现,问题消失。原因在于system()实际上调用了fork()/vfork()。

为什么在多线程调用fork会出现问题呢?我分析是因为fork会把当前进程复制到子进程,子进程也是多线程。注意在子进程执行fork()-exec()这段时间,子进程的其他线程也在运行,同时信号量也被复制到子进程中。因为父子进程有独立的信号量来保护设备,这样父进程访问设备的时候,子进程也可以访问设备,于是出现问题。

  linux下创建子进程和多线程冲突的根本原因在于fork会复制当前进程,而Windows创建子进程就没有这个问题。为什么会这样呢?个人认为可能是历史原因造成的。早期的unix注意是作为服务器使用,例如web/ftp服务等。在没有多线程支持的年代,服务器支持多用户访问支持的方法就是为每个用户创建一个服务子进程。服务子进程通常就是服务器本身,因此提供一个fork调用,是可以提高效率的。但是当初设计fork调用的时候,并没有考虑到多线程,导致与多线程冲突。unix的历史负担很多,比如线程局部存储(TLS),个人认为就是为了解决早期程序设计者喜欢大量使用全局变量和多进程提出的。

 

那如果确实需要在多线程程序里运行另一个程序(而且只有可执行文件没有源代码)怎么办呢?可以把要执行的程序包装一下,多线程的主程序通过进程间通信的方式包装后的子进程通信。

 

与关于第2点多线程与signal机制的问题,网上很多,大家搜索一下就有了,不多说了

0 0
原创粉丝点击