Linux多线程与fork()函数

这篇具有很好参考价值的文章主要介绍了Linux多线程与fork()函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

4.1多线程中使用进程复制

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
void* fun(void* arg)
{
    for(int i=0;i<5;++i)
    {
        printf("fun run pid=%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 run pid=%d\n",getpid());
        sleep(1);
    }
    pthread_join(id,NULL);
    exit(0);
}

在使用fork()函数之后,没有判断返回值大于0还是等于0,则之后的代码在父子进程都会执行。

Linux多线程与fork()函数

 文章来源地址https://www.toymoban.com/news/detail-515680.html

pid相同的为父进程中的两个线程,pid不同的为子进程的线程。此时子进程启动的为父进程的主线程所在的执行路径。

当把fork()从主线程中放到子线程中时:

void* fun(void* arg)
{
    fork();//
    for(int i=0;i<5;++i)
    {
        printf("fun run pid=%d\n",getpid());
    	sleep(1);
    }
}
int main()
{
    pthread_t id;
    pthread_create(&id,NULL,fun,NULL);
    for(int i=0;i<5;++i)
    {
        printf("main run pid=%d\n",getpid());
        sleep(1);
    }
    pthread_join(id,NULL);
    exit(0);
}

Linux多线程与fork()函数

 

pid相同的为父进程中的两个线程,pid不同的为子进程的线程。此时子进程启动的为父进程的子线程所在的执行路径(线程)。

从上述两种情况能看到,在复制子进程时fork()函数父进程的资源状态等会全部复制过来,但是只有一条执行路径(线程),只会将fork()函数所在的执行路径(线程)进行复制。也就意味着,复制的子进程只有一条执行路径(线程),该路径是父进程中fork()函数所在的路径(线程)。

4.2多线程中互斥锁与fork()函数

pthread_mutex_t mutex;
void* fun(void* arg)
{
    pthread_mutex_lock(&mutex);
    printf("theread fun lock\n");
    sleep(5);
    pthread_mutex_unlock(&mutex);
    printf("thread fun unlock\n");
}
int main()
{
    pthread_mutex_init(&mutex,NULL);
    pthread_t id;
    pthread_create(&id,NULL,fun,NULL);
    sleep(1);
    pid_t pid=fork();
    if(pid==-1)
    {
        exit(1);
    }
    if(pid==0)
    {
        printf("child 准备加锁\n");
        pthread_mutex_lock(&mutex);
        printf("child 加锁成功\n");
        pthread_mutex_unlock(&mutex);
        exit(0);
    }
    wait(NULL);
    printf("main over\n");
    pthread_join(id,NULL);
    exit(0);
}

运行结果:

Linux多线程与fork()函数

 

原因:父进程的子线程先加锁并打印加锁信息,等待五秒钟,此时子进程打印准备加锁后阻塞住,等到父进程的子线程解锁并打印信息后子进程依然在阻塞,没有加上锁,所以子进程和父进程用的不是同一个锁。子进程一直不能加锁,说明子进程的锁一直处于加锁状态没有解锁,在fork()之前睡眠一秒钟,这一秒钟足够父进程的子线程加锁,所以子进程在复制父进程时,将父进程的加锁状态复制过来

当去掉上述代码中的sleep()语句后,复制子进程时,子进程的锁的状态就变成不确定随机的,因为是在启动父进程的子线程后才开始复制的,复制时可能子线程加锁还没解锁,也可能子进程加完锁又解开了。

为了避免这种子进程不确定锁的状态,需要在父进程中挑取一个没人加锁的状态进行进程的复制,可以在fork()前进行加锁,在fork()后再进行解锁。当如果多出使用fork()函数这样的方法比较繁杂,于是就使用函数pthread_atfork(父进程加锁函数,父进程解锁函数,子进程解锁函数),当程序中使用fork()函数时,会先调用父进程加锁函数,然后在fork()结束后在父进程调用父进程解锁函数,然后在子进程中调用子进程解锁函数。

pthread_mutex_t mutex;
void fun_mutex_lock()
{
    pthread_mutex_lock(&mutex);
}
void fun_mutex_unlock()
{
    pthread_mutex_unlock(&mutex);
}
void child_mutex_unlock()
{
    pthread_mutex_unlock(&mutex);
}
void* fun(void* arg)
{
    pthread_mutex_lock(&mutex);
    printf("theread fun lock\n");
    sleep(5);
    pthread_mutex_unlock(&mutex);
    printf("thread fun unlock\n");
}
int main()
{
    pthread_mutex_init(&mutex,NULL);
    pthread_atfork(fun_mutex_lock,fun_mutex_unlock,child_mutex_unlock);
    pthread_t id;
    pthread_create(&id,NULL,fun,NULL);
    sleep(1);
    pid_t pid=fork();
    if(pid==-1)
    {
        exit(1);
    }
    if(pid==0)
    {
        printf("child 准备加锁\n");
        pthread_mutex_lock(&mutex);
        printf("child 加锁成功\n");
        pthread_mutex_unlock(&mutex);
        exit(0);
    }
    wait(NULL);
    printf("main over\n");
    pthread_join(id,NULL);
    exit(0);
}

Linux多线程与fork()函数

 

到了这里,关于Linux多线程与fork()函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • fork()函数创建子进程

    fork()用于创建子进程, 一次调用 会有 两个返回 (return),一次返回给父进程子进程的PID(Process ID),一次返回给子进程,其返回值为0. 返回值=0,子进程在运行 返回值0,父进程在运行 返回值0,fork()调用出错 进程获取 自己的PID:getpid() 进程获取 父进程PID:getppid() 由于一个进

    2023年04月08日
    浏览(42)
  • Fork() 函数:“父” 与 “子” 进程的交互(进程的创建)

    前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的一些知识,也学习了一些Linux的基本操作,也了解并学习了有关Linux开发工具vim 、gcc/g++ 使用、yum工具以及git 命令行提交代码也相信大家都掌握的不错,上一篇文章我们了解了关于进程的基本概念,今

    2024年02月08日
    浏览(36)
  • Linux入门之多线程|线程|进程基本概念及库函数

    目录 一、线程 1.线程的概念 补充知识点:页表 2.线程的优点 3.线程的缺点 4.线程异常 5.线程用途 二、线程与进程的区别与联系 三、关于进程线程的问题 0.posix线程库 1.创建线程 关于pthread_create的后两个参数 1.传入指针 2.传入对象 2.线程终止 3.取消线程 4.线程等待(等待线程

    2024年02月10日
    浏览(39)
  • 【Linux进程】查看进程&&fork创建进程

    目录 前言  1. 查看进程  2. 通过系统调用创建进程-fork初识 总结          你有没有想过在使用Linux操作系统时,后台运行的程序是如何管理的?在Linux中,进程是一个非常重要的概念。本文将介绍如何查看当前运行的进程,并且讨论如何使用fork创建新的进程。通过了解这些

    2024年01月22日
    浏览(54)
  • fork函数如何创建进程,exit/_exit函数如何使进程终止的详细分析与代码实现

    🎊【进程通信与并发】专题正在持续更新中,进程,线程,IPC,线程池等的创建原理与运用✨,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 -  ​​​​​​并发与进程通信 🍻欢迎大家  🏹  点赞👍  评论📨  收藏⭐️ 📌个人主页 - 勾栏听曲

    2024年02月05日
    浏览(47)
  • 【Linux初阶】fork进程创建 & 进程终止 & 进程等待

     🌟hello,各位读者大大们你们好呀🌟 🍭🍭系列专栏:【Linux初阶】 ✒️✒️本篇内容:fork进程创建,理解fork返回值和常规用法,进程终止(退出码、退出场景、退出方法、exit),进程等待(wait、waitpid),阻塞等待和非阻塞等待 🚢🚢作者简介:本科在读,计算机海洋

    2024年02月06日
    浏览(52)
  • Linux中的进程、fork、进程状态、环境变量

            进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct 在Linux中描述进程的结构体叫做task_struct。task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包

    2024年02月10日
    浏览(44)
  • Linux------进程的fork()详解

    目录 前言 一、fork()的使用 二、fork()的返回值 我们为什么要创建子进程? 父进程与子进程的分流 三、fork的一些难理解的问题 1.fork干了什么事情? 2.fork为什么会有两个返回值  3.fork的两个返回值,为什么会给父进程返回子进程pid,给子进程返回0? 4.fork之后,父子进程谁先

    2024年01月18日
    浏览(40)
  • 【TCP/IP】多进程服务器的实现(进阶) - 进程的概念及fork函数

    目录 进程的概念及应用 进程的定义 进程的ID fork函数(进程创建函数)         多进程(以及多线程)是现代计算机网络的精髓。在之前,我们所做的诸如回声服务器、回声客户端、文件收发等都是偏向基础的单进程应用。而经过前面的铺垫,我们对Socket也有了一定了解

    2024年02月09日
    浏览(56)
  • Linux:创建进程 -- fork,到底是什么?

     相信大家在初学进程时,对fork函数创建进程一定会有很多的困惑,比如: 1.fork做了什么事情??  2.为什么fork函数会有两个返回值? 3.为什么fork的两个返回值,会给父进程谅回子进程pid,给子进程返回0? 4.fork之后:父子进程谁先运行?? 5.如何理解同一个变量,会有不同的值?? 本

    2024年02月05日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包