子进程继承父进程中互斥锁的讨论

1. 引言 首先明确一个问题:如果一个多线程程序的某个线程调用了fork函数,那么新创建的子进程里是不会自动创建和父进程相同数量的线程的,它只是调用fork的那个线程的完整复制。并且,子进程会自动继承父进程中(包括父进程在调用fork之前创建的线程)互斥锁的状态。也就是说,父进程中已经被加锁的互斥锁在子进程中也是被锁住的。这就引起了一个问题:子进程可能不清楚从父进程继承过来的互斥锁的具体状态(是加锁状态还是解锁状态)。这个互斥锁可能被加锁了,,但并不是由调用fork函数的那个线程锁住的,而是由其他线程锁住的。如果是这种情况,则子进程若再次对该互斥锁执行加锁操作就会导致死锁。下面讨论子进程继承父进程互斥锁的几种情况。 2. 继承父进程创建的锁

pthread_mutex_t mutex;int main(){pthread_mutex_init(&mutex,NULL);pthread_mutex_lock(&mutex);int pid = fork();if(pid<0){pthread_join(id,NULL);pthread_mutex_destroy(&mutex);return 1;}else if(pid == 0){printf(“I am in the child,want to get the lock\n”);pthread_mutex_lock(&mutex);printf(“I am running here,oop…\n”);pthread_mutex_unlock(&mutex);printf(“I unlocked\n”);exit(0);}else{sleep(3);pthread_mutex_unlock(&mutex);printf(“unlocked\n”);wait(NULL);}pthread_join(id,NULL);pthread_mutex_destroy(&mutex);return 0;}

死锁!可以看到,父进程之前先加了锁,子进程继承了加锁的状态后,尝试加锁时被阻塞,即便3秒后父进程解了锁,子进程还是不能进行加锁操作,因为fork之后子进程对父进程的动作是不可见的,因此子进程陷入了永远的阻塞状态。 3. 父进程的子线程在fork前执行了加锁操作

pthread_mutex_t mutex;void* another(void* arg){printf(“in child thread\n”);pthread_mutex_lock(&mutex);printf(“lock\n”);sleep(5);pthread_mutex_unlock(&mutex);printf(“unlocked the mutex\n”);}int main(){pthread_mutex_init(&mutex,NULL);pthread_t id;pthread_create(&id,NULL,another,NULL);sleep(1);int pid = fork();if(pid<0){pthread_join(id,NULL);pthread_mutex_destroy(&mutex);return 1;}else if(pid == 0){printf(“I am in the child,want to get the lock\n”);pthread_mutex_lock(&mutex);printf(“I am running here,oop…\n”);pthread_mutex_unlock(&mutex);printf(“I unlocked\n”);exit(0);}else{wait(NULL);}pthread_join(id,NULL);pthread_mutex_destroy(&mutex);return 0;}

死锁!fork之前睡眠1秒是为了让子线程先执行加锁。可以看到,子线程加锁后,子进程继承了互斥锁的状态,无法执行加锁操作,被阻塞。即便后来子线程解了锁,子进程还是继续阻塞。说明子进程只是继承了锁的状态,对后来的解锁动作并不可见。 4. 子线程在fork之后加锁

pthread_mutex_t mutex;void* another(void* arg){printf(“in child thread\n”);sleep(2);pthread_mutex_lock(&mutex);printf(“lock\n”);pthread_mutex_unlock(&mutex);printf(“unlocked the mutex\n”);}int main(){pthread_mutex_init(&mutex,NULL);pthread_t id;pthread_create(&id,NULL,another,NULL);int pid = fork();if(pid<0){pthread_join(id,NULL);pthread_mutex_destroy(&mutex);return 1;}else if(pid == 0){printf(“I am in the child,want to get the lock\n”);pthread_mutex_lock(&mutex);printf(“I am running here,oop…\n”);sleep(5);pthread_mutex_unlock(&mutex);printf(“I unlocked\n”);exit(0);}else{wait(NULL);}pthread_join(id,NULL);pthread_mutex_destroy(&mutex);return 0;}

正常!在fork之前子线程还没有加锁,子进程成功加锁,再解锁前,子线程也执行了加锁操作,之后两者都顺利解了锁。说明子进程继承的只是fork之前父进程(包括其子线程)已执行过的锁操作状态,fork之后父子各自对锁的操作是不可见的。 5. 子线程创建的线程中执行了加锁

pthread_mutex_t mutex;void* another(void* arg){printf(“in child thread\n”);// sleep(2);pthread_mutex_lock(&mutex);printf(“lock\n”);sleep(5);pthread_mutex_unlock(&mutex);printf(“unlocked the mutex\n”);}void* childpthread(void* arg){pthread_t thid;pthread_create(&thid,NULL,another,NULL);pthread_join(thid,NULL);}int main(){pthread_mutex_init(&mutex,NULL);pthread_t id;pthread_create(&id,NULL,childpthread,NULL);sleep(3);int pid = fork();if(pid<0){pthread_join(id,NULL);pthread_mutex_destroy(&mutex);return 1;}else if(pid == 0){printf(“I am in the child,want to get the lock\n”);pthread_mutex_lock(&mutex);printf(“I am running here,oop…\n”);sleep(5);pthread_mutex_unlock(&mutex);printf(“I unlocked\n”);exit(0);}else{wait(NULL);}pthread_join(id,NULL);pthread_mutex_destroy(&mutex);return 0;}

死锁!锁的状态仍然被子进程继承了。

人生就像一杯没有加糖的咖啡,喝起来是苦涩的,

子进程继承父进程中互斥锁的讨论

相关文章:

你感兴趣的文章:

标签云: