一:概念
当在一个进程当中的某个线程当中调用了fork函数后,其子进程具有如下特征:
(1)子进程通过继承整个地址空间的副本,也从父进程那里继承了所有互斥量、读写锁和条件变量的状态。
(2)在子进程内部只存在一个线程,它是由父进程中调用fork的线程的副本构成的。

综合以上两点,带来了如下思考:
fork出来的子进程继承了所有的锁状态,但是,子进程只含有父进程当中的一个线程(也就是在父进程当中调用fork的那个线程),如果在父进程当中有A,B,C三个线程,在A线程当中调用了fork,但是,父进程当中的A,B,C三个进程都使用了某把锁,而这个时候,根据(1)(2)两点,子进程只是知道父进程当中的A线程的锁状态而已,它并不知道B,C两个线程的锁状态。

所以,有一个函数是用来统一锁的状态的。

#include <pthread.h>
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
返回值:若成功则返回0,否则返回错误编号

二:范例演示
我们根据一当中的(2)来验证一下,在某个进程的某个线程当中调用了fork以后带来的结果:

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

/* 定义互斥量 */
pthread_mutex_t mtx;
/* 互斥量属性 */
pthread_mutexattr_t mtx_attr;


void err_exit(const char *err_msg)
{
    printf("error:%s\n", err_msg);
    exit(1);
}

void *fun(void *arg)
{

    int pid = fork();
    while(1)
    {
        printf("fun线程正在运行!!!\n");
        printf("fun->getpid() = %d\n",getpid());
        sleep(2);
    }
    return NULL;
}

/* 线程函数 */
void *thread_fun(void *arg)
{
    while (1)
    {
        printf("thread_fun线程正在运行!!!\n");
        printf("thread_fun->getpid() = %d\n",getpid());
        sleep(2);
    }
    return NULL;
}

int main(void)
{
    pthread_t tid,tid1;

     /* 初始化互斥量属性 */
    if (pthread_mutexattr_init(&mtx_attr) == -1)
        err_exit("pthread_mutexattr_init()");

    /* 设置互斥量属性 */
    if (pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_NORMAL) == -1)
        err_exit("pthread_mutexattr_settype()");

     /* 初始化互斥量 */
    if (pthread_mutex_init(&mtx, &mtx_attr) == -1)
        err_exit("pthread_mutex_init()");

     /* 创建一个线程 */
    if (pthread_create(&tid, NULL, thread_fun, NULL)== -1)
        err_exit("pthread_create()");

       /* 创建一个线程 */
    if (pthread_create(&tid1, NULL, fun, NULL)== -1)
        err_exit("pthread_create()");


    while (1)
    {
        sleep(2);
    }
    return 0;
}

在这里插入图片描述
可以看到,fun函数当中打印出了两个PID,所以子进程当中,是只含有一个线程而已,即fun函数,它只会执行fun函数里面的代码,但是却会继承所有的锁状态。

三:pthread_atfork函数学习

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

pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;

void prepare(void)
{
    printf("preparing locks...\n");
    pthread_mutex_lock(&lock1);
    pthread_mutex_lock(&lock2);
}

void parent(void)
{
    printf("parent unlocking locks...\n");
    pthread_mutex_unlock(&lock1);
    pthread_mutex_unlock(&lock2);
}

void child(void)
{
    printf("child unlocking locks...\n");
    pthread_mutex_unlock(&lock1);
    pthread_mutex_unlock(&lock2);
}

void *thr_fn(void *arg)
{
    printf("thread started...\n");
    pause();
    return(0);
}

int main(void)
{
    int        err;
    pid_t        pid;
    pthread_t    tid;
    
#if defined(BSD) || defined(MACOS)
    printf("pthread_atfork is unsupported\n");
#else
    if((err = pthread_atfork(prepare, parent, child)) != 0)
        err_exit(err, "can't install fork handlers");
    err = pthread_create(&tid, NULL, thr_fn, 0);
    if(err != 0)
        err_exit(err, "can't create thread");
    sleep(2);
    printf("parent about to fork...\n");    
    if((pid = fork()) < 0)
        err_quit("fork failed");
    else if(pid == 0)    /* child */
        printf("child returned from fork\n");
    else    /* parent */
        printf("parent returned from fork\n");
#endif
    exit(0);
}

版权声明:本文为qq_38158479原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_38158479/article/details/116999240