一:概念
当在一个进程当中的某个线程当中调用了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 版权协议,转载请附上原文出处链接和本声明。