2017-08-25 50 views
3

分叉,我有以下程序:而持有锁

#include <pthread.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <iostream> 


int main() { 
    pthread_mutex_t lock_; 
    pthread_mutexattr_t ma; 
    pthread_mutexattr_init(&ma); 
    pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED); 
    pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK); 
    pthread_mutex_init(&lock_, &ma); 

    pthread_mutex_lock(&lock_); 

    if(fork()==0) { 
     std::cout << "child" << std::endl; 
     pthread_mutex_lock(&lock_); 
     std::cout << "finish" << std::endl; 
    } else { 
     std::cout << "parent" << std::endl; 
     sleep(1); 
     pthread_mutex_lock(&lock_); 
     std::cout << "parent done" << std::endl; 
    } 

} 

我看到EIS的家长可以重新锁定互斥的行为,而不是孩子。我希望fork()能够分离当前线程的所有上下文,所以孩子最终会锁定它已锁定的锁(IE,我不想共享锁 - 两个进程都有自己的锁是我想要的)。为什么这不起作用/我该如何做到这一点?

+0

[fork without exec,pthread \ _mutex \ _t共享对象使用]的可能重复(https://stackoverflow.com/questions/20557185/fork-without-exec-and-pthread-mutex-t-used -by-shared-object) –

+0

因此,没有办法让当前线程锁定互斥锁,并且在fork之后,子进程和父进程的互斥锁都在该进程中工作? –

回答

4

这不起作用,仅仅是因为它被明确记录为不起作用,有点令人困惑。 fork()和多线程进程不能很好地一起玩。

尽管fork()手册页最初声称它“通过复制调用过程创建了一个新过程”,但这是一个小小的谎言。如果fork()真的做到了这一点,并重复了整个过程,它必须忠实地复制所有进程的执行线程。因为这就是你的流程的全部内容:构成整个流程的所有执行线程。

但是,这不是什么情况。

如果keep reading the fork(2) manual page,你会得到这部分:

子进程与单个线程的一个 称为fork()的创建。

这将是你的报警线索号码#1 fork()并不真正重复整个过程。它只复制其执行线程中的一个。

母体的整个虚拟地址空间是 在子复制的,包括互斥的状态,病症 变量和其他并行线程对象;

现在,停下来想一想,这意味着什么:只有一个执行线程被分叉,但所有这些都在子进程中被仔细复制。我们必须从中得出的结论相当难看。

如果你仔细想一想:子进程继续执行一个独立的执行线程,这个线程的互斥锁最初被其他线程锁定。但是其他线程在子进程中不存在。它不是分叉的。只有一个线程分叉。

这实际上是澄清在pthread_atfork(3) manual page

例如,在该呼叫到叉的时间(2),其它线程可能 已经锁定其是在用户空间内存 可见互斥在孩子身上复制。这样的互斥锁永远不会被解锁,因为放置锁的线程不会在子中复制。

因此,底线,在示例代码的子进程结束固定装有一堆不再在任何形式的有效状态互斥的袋子,在子进程。

+0

没错,我读到了 - 这似乎暗示着,如果线程A锁定了互斥锁,然后线程B分叉了,但是如果线程A锁定,然后线程A分叉,它就会工作。 –