17-LINUX--线程与fork()

一.多线程程序+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);

}

相关推荐

最近更新

  1. Unity 常用取整方法

    2024-05-11 20:14:09       0 阅读
  2. 华为机考真题 -- 攀登者1

    2024-05-11 20:14:09       0 阅读
  3. Linux内核 -- 内存管理之scatterlist结构使用

    2024-05-11 20:14:09       0 阅读
  4. 【国产开源可视化引擎Meta2d.js】数据

    2024-05-11 20:14:09       1 阅读
  5. Elasticsearch 面试题指南

    2024-05-11 20:14:09       0 阅读
  6. Linux笔记之iftop查看特定IP地址吞吐量

    2024-05-11 20:14:09       0 阅读
  7. 量化交易在不同经济周期中的表现

    2024-05-11 20:14:09       0 阅读

热门阅读

  1. 算法详解——穷举法

    2024-05-11 20:14:09       11 阅读
  2. mysql5.x 的某些神奇问题

    2024-05-11 20:14:09       11 阅读
  3. 全志A133 android10 增加开机脚本

    2024-05-11 20:14:09       8 阅读
  4. Hive优化(1)——分桶采样

    2024-05-11 20:14:09       11 阅读