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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lyh__521/article/details/45921515

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


#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<wait.h>

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前执行了加锁操作


#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
#include<wait.h>

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之后加锁


#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
#include<wait.h>

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. 子线程创建的线程中执行了加锁


#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
#include<wait.h>

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;
}

这里写图片描述
死锁!锁的状态仍然被子进程继承了。

没有更多推荐了,返回首页