让我解释一下:我已经在Linux上开发了一个应用程序,它派生并执行一个外部二进制文件,然后等待它完成。结果通过shm文件传递,这些文件是fork +进程所特有的。整个代码都封装在一个类中。
现在,我正在考虑将进程线程化,以加快速度。拥有许多不同的类函数实例,派生并并发执行二进制文件(使用不同的参数),并使用自己独特的shm文件传递结果。
这个线程安全吗?如果我在一个线程中派生,除了安全之外,还有什么我需要注意的吗?任何建议或帮助都是非常感谢的!
发布于 2011-05-21 12:52:35
问题是fork()只复制调用线程,子线程中保存的任何互斥锁都将永远锁定在派生的子线程中。pthread解决方案是pthread_atfork()处理程序。其想法是您可以注册3个处理程序:一个prefork、一个父处理程序和一个子处理程序。当fork()发生时,prefork在fork之前被调用,并期望获得所有应用程序互斥锁。父进程和子进程必须分别释放父进程和子进程中的所有互斥锁。
不过,这还不是故事的结尾!库调用pthread_atfork来注册特定于库的互斥锁的处理程序,例如Libc就是这样做的。这是一件好事:应用程序不可能知道第三方库持有的互斥锁,所以每个库都必须调用pthread_atfork,以确保在发生fork()时清除自己的互斥锁。
问题是,为不相关的库调用pthread_atfork处理程序的顺序是未定义的(这取决于程序加载这些库的顺序)。因此,这意味着从技术上讲,由于竞争条件,prefork处理程序内部可能会发生死锁。
例如,考虑以下序列:
fork()
这就是你的死锁,它与你自己的互斥锁或代码无关。
这实际上发生在我曾经参与的一个项目中。我当时发现的建议是选择fork或线程,但不能两者都选。但对于某些应用程序来说,这可能并不实用。
发布于 2011-05-21 12:20:26
只要您非常注意fork和exec之间的代码,那么在多线程程序中派生是安全的。在该范围内,您只能进行可重入(也称为异步安全)系统调用。理论上,您不允许在那里使用malloc或free,尽管在实践中默认的Linux分配器是安全的,并且Linux库开始依赖它,最终结果是您必须使用默认的分配器。
发布于 2011-05-21 08:35:16
虽然您可以将Linux的NPTL pthreads(7)支持用于您的程序,但正如您在fork(2)问题中所发现的那样,线程在Unix系统上并不适合。
由于fork(2)在现代系统上是一个非常廉价的操作,当您有更多的处理要执行时,您可能会做得更好,只对您的进程执行fork(2)。这取决于您打算来回移动多少数据,forked进程的无共享原则对于减少共享数据but很有帮助,但这确实意味着您要么使用need to create pipes to move data between processes,要么使用共享内存(shmget(2)或shm_open(3))。
但是,如果您选择使用线程,则可以使用fork(2)手册页中的以下提示来fork(2)一个新进程:
\* The child process is created with a single thread — the one that called fork(). The entire virtual address space of the parent is replicated in the child, including the states of mutexes, condition variables, and other pthreads objects; the use of pthread\_atfork(3) may be helpful for dealing with problems that this can cause.
https://stackoverflow.com/questions/6078712
复制相似问题