一.多线程程序+fork()
多线程出现fork()后,只复制一条执行路径,是fork()所在的那条执行路径
主程序+fork()示例代码:
include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include<unistd.h>void* fun(void* arg)
{for(int i=0;i<5;i++){printf("fun id=%d\n",getpid());sleep(1);}
}int main()
{pthread_t id;pthread_create(&id,NULL,fun,NULL);fork();for(int i=0;i<5;i++){printf("main pid=%d\n",getpid());sleep(1);}pthread_join(id,NULL);
}
~
fork()在那个路径,就复制那条路径
在复制的过程中,若被复制函数包含锁这类的代码,会被复制当前锁的状态,但复制完成以后各自有锁,互不影响。
因为这个特性,会导致锁的在其他线程加锁的过程中,主线程或子线程想要加锁会被阻塞。由此我们引入pthread_atfork(*prepare,**parent,*child):
二.pthread_atfork()
在父进程调用fork函数派生子进程的时候,如果父进程创建了pthread的互斥(pthread_mutex_t)对象,那么子进程将自动继承父进程中互斥锁对象,并且互斥锁的状态也会被子进程继承下来:如果父进程中已经加锁的互斥锁在子进程中也是被锁住的,如果在父进程中未加锁的互斥锁在子进程中也是未加锁的。在父进程调用fork之前所创建的pthread_mutex_t对象会在子进程中继续有效,而pthread_mutex_t对象通常是全局对象,会在父进程的任意线程中被操作(加锁或者解锁),这样就无法通过简单的方法让子进程明确知道被继承的 pthread_mutex_t对象到底有没有处于加锁状态。
prepare:将在fork调用创建出子进程之前被执行,它可以给父进程中的互斥锁对象明明确确上锁。这个函数是在父进程的上下文中执行的,正常使用时,我们应该在此回调函数调用 pthread_mutex_lock 来给互斥锁明明确确加锁,这个时候如果父进程中的某个线程已经调用pthread_mutex_lock给互斥锁加上了锁,则在此回调中调用 pthread_mutex_lock 将迫使父进程中调用fork的线程处于阻塞状态,直到prepare能给互斥锁对象加锁为止。
parent: 是在fork调用创建出子进程之后,而fork返回之前执行,在父进程上下文中被执行。它的作用是释放所有在prepare函数中被明明确确锁住的互斥锁。
child: 是在fork返回之前,在子进程上下文中被执行。和parent处理函数一样,child函数也是用于释放所有在prepare函数中被明明确确锁住的互斥锁。
函数成功返回0, 错误返回错误码
prepare是在fork调用之前会被调用的,parent在fork返回(进入)父进程之前调用,child在fork返回子进程之前调用。如果在prepare中加锁所有的互斥量,在parent和child中解锁所有的互斥量,那么在fork返回之后,互斥量的状态就是未加锁。
示例代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/wait.h>pthread_mutex_t mutex;void prepare(void)
{pthread_mutex_lock(&mutex);
}
void parent(void)
{pthread_mutex_unlock(&mutex);
}
void child(void)
{pthread_mutex_unlock(&mutex);
}
void* fun(void*arg)
{pthread_mutex_lock(&mutex);printf("fun lock\n");sleep(3);pthread_mutex_unlock(&mutex);printf("fun unlock\n");
}int main()
{pthread_mutex_init(&mutex,NULL);pthread_t id;pthread_create(&id,NULL,fun,NULL);sleep(1);//子进程已加锁pthread_atfork(prepare,parent,child);pid_t pid = fork();if(pid == -1){exit(1);}if(pid == 0){printf("child 准备加锁\n");pthread_mutex_lock(&mutex);printf("子进程加锁成功\n");pthread_mutex_unlock(&mutex);exit(0);}wait(NULL);printf("main over\n");pthread_join(id,NULL);exit(0);}