fork()需要注意的一些问题

多线程下的fork问题(模拟与解决) 目录前言1. 浅谈在多线程下的fork问题2. 死锁问题的模拟实现3. 解决办法 前言 有关进程、多线程、fork的概念,请看我之前写的这两篇文章。 Linux:进程控制(进程创建、进程终止、进程等待、进程程序替换) Linux:详解多线程(线程概念、线程控制—线程创建、线程终止、线程等待)(一) 1. 浅谈在多线程下的fork问题fork函数创建出一个子进程的时候,子进程拷贝父进程的进程虚拟地址空间,并且也会从父进程中拷贝一份相应的内存数据子进程中,这是我们所知道的在单进程的情况下它是这样的, 阅读详情

        fork函数用户创建一个和自身一样的子进程,子进程是父进程的副本,子进程得到与父进程用户级虚拟地址空间相同的(但是独立的)一份拷贝,包括文本、数据和bss段、堆以及用户栈等。子进程还获得与父进程任何打开文件描述符相同的拷贝(比如子进程可以读写父进程中任何打开的文件),他们有完全独立的拷贝(当然linux使用了cow技术,只有改变才会真的拷贝),就是说两边的修改互不影响,父进程和子进程之间最大的区别在于它们有着不同的PID。一次调用两次返回,> 0表示是父进程, == 0表示是子进程。fork产生的问题主要是:

1) 拷贝了父进程的资源,缓冲区等,所以子进程是有状态的,比如我们调用printf的时候会把数据写入缓冲区,子进程也会继承过来,那么在子进程进行打印的时候就可能会打印出本来在父进程写入缓冲区的内容。


2)fork的时候只复制当前线程到子进程,其他线程就没有了,这就会导致很多问题,比较典型的问题就是锁不被释放。

       比如我们在父进程中有一段代码 加锁之后进行了fork,而这个解锁工作是在另外一个线程进行的,那么子进程会继承这个锁(处于锁住状态),导致锁不能被释放。

       那么一般解决这个问题的方法有几种: 

a. 确保父进程是单线程的;

b. fork之后立马调用exec函数,这样会使用完全新的地址空间替换原有的空间。

c. fork_atfork
函数原型为 int pthread_atfork(void (*prepare)(void), void (*parent)void(), void (*child)(void));
prepare处理函数由父进程在fork创建子进程前调用,这个函数的任务是获取父进程定义的所有锁。
parent处理函数是在fork创建了子进程以后,但在fork返回之前在父进程环境中调用的。它的任务是对prepare获取的所有锁解锁。
child处理函数在fork返回之前在子进程环境中调用,与parent处理函数一样,它也必须解锁所有prepare中所获取的锁。
因为子进程继承的是父进程的锁的拷贝,所有上述并不是解锁了两次,而是各自独自解锁。可以多次调用pthread_atfork函数从而设置多套fork处理程序,但是使用多个处理程序的时候。处理程序的调用顺序并不相同。parent和child是以它们注册时的顺序调用的,而prepare的调用顺序与注册顺序相反。这样可以允许多个模块注册它们自己的处理程序并且保持锁的层次(类似于多个RAII对象的构造析构层次)。

需要注意的是pthread_atfork只能清理锁,但不能清理条件变量。在有些系统的实现中条件变量不需要清理。但是在有的系统中,条件变量的实现中包含了锁,这种情况就需要清理。另外一些隐含的函数比如malloc我们也是无法干预的。所以此函数不能完全规避问题。


参考 

谨慎使用多线程中的fork http://www.cnblogs.com/liyuan989/p/4279210.html

多线程程序中fork导致的一些问题  http://www.cnblogs.com/zxtp/p/5147356.html


Windows 11安装 SQLServer 2008 R2 失败问题处理 Windows 11安装SQL Server 2008 R2失败解决方案 由于Windows 11移除了对PowerShell 2.0的支持,导致SQL Server 2008 R2安装失败。经过多次尝试,最终通过**方案六(修改注册表模拟PowerShell 2.0环境)**成功安装。其他可行方案包括: 使用SP3集成版安装包 通过命令行跳过检查(/SUPPRESSPOWERShellCHECK参数) 创建特殊配置文件 替代方案建议: 使用Docker容器运行 在虚拟机中安装 升级到新版SQL Serve 阅读详情

相关推荐

PHP - 使用 pcntl_fork() 执行多进程的详细解析与编程示例

pcntl_fork() 函数的作用是创建一个子进程,该子进程是父进程的一个副本,从调用 pcntl_fork() 的位置开始执行。本文将详细解析 pcntl_fork() 函数的执行过程,并提供相应的源代码示例,帮助你理解和应用多进程编程的概念。子进程是父进程的副本,它们之间的变量和资源并共享。如果返回值大于 0,表示当前进程是父进程,返回的值是子进程的 PID。本文详细解析了在 PHP 中使用 pcntl_fork() 函数执行多进程的过程,并提供了相应的源代码示例来帮助读者理解多进程编程的概念。

HackSquad的博客 959

Linux进程管理——fork()和写时复制

但是虚拟的存储空间映射到物理存储空间的过程中采用了写时拷贝技术(具体的操作大小是按着页控制的),该技术主要是将多进程中同样的对象(数据)在物理存储其中只有一个物理存储空间,而当其中的某一个进程试图对该区域进行写操作时,内核就会在物理存储器中开辟一个新的物理页面,将需要写的区域内容复制到新的物理页面中,然后对新的物理页面进行写操作。在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间同,但其对应的物理空间是同一个。

m0_74282605的博客 267

链接文件及功能安全:基于Tasking的LSL链接文件知识点梳理及实际应用分析

本文旨在记录研究链接文件时所遇到的问题及个人理解,以便日后查阅。在探索过程中,我遇到了诸多问题,同时对链接文件有了初步的认识。通过记录这些问题与理解,我希望能够为后续的研究提供清晰的思路和有价值的参考。这仅是对研究过程的总结,更是对未来学习和实践的有力支持。

梦想技术家 1068

fork注意事项

1.Linux中进程的创建方式(系统调用: fork、clone、vfork) (1)fork()带参数)和clone()(带参数): 这两者的区别在于fork()是全部复制而clone()则可以将资源有选择的复制给子进程,而没有复制的数据结构则是通过指针的复制让子进程共享,极端情况下一个进程可以clone()出一个线程。所以系统调用fork()无参数,而clone()则带有参数 (2)v...

Monster7559的博客 502

fork注意事项

fork是需要注意父进程中的哪些资源是会被子进程继承的 用于管理动态内存和文件描述符的RAII类可以正常工作 #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <string.h> #include <fcntl.h> // open pid_t g_parent_pid = 0; #define NEW_BUF_SIZE 6 // 子进程会继承

yqq1997的博客 381

linux fork() 函数使用注意问题

fork 函数从哪里开始执行 #include <unistd.h>; #include <sys/types.h>; main () { pid_t pid; pid=fork(); // 1)从这里开始程序分岔,父子进程都从这一句开始执行一次 if (pid < 0) printf("error!"); else if (pid == 0) printf("chi.

huifeidedabian的博客 245

linux fork()笔记

源代码,通过输出测试fork()如何创建一个新的进程; int main(int argc, char const *argv[]) {   pid_t pid =1;   static int a=1;   pid = fork();   std::cout   a++;   pid = fork();   std::cout   a++;   pid = fork();

zhuzeyu22的博客 823

[python] os.fork

父进程会打印自己的 PID 和子进程的 PID,而子进程只会打印自己的 PID。这个函数在父进程中返回新创建的子进程的进程ID(PID),而在子进程中则返回 0。系统调用非常基础且强大,允许操作系统创建一个新的进程,这个新进程是调用它的进程(父进程)的副本。系统调用会创建一个新的进程,新进程是原始进程的一个副本,包括代码、数据和资源等。时,操作系统会复制当前进程的所有信息,并将这个复制的进程作为新的子进程返回给父进程。后,父进程和子进程是相互独立的,各自有自己的内存空间和资源。也就是说,如果父进程在。

言之。 1万+

fork()函数与Linux中的多线程编程

转载请说明出处:http://blog.csdn.net/cywosp/article/details/27316803 一、fork()函数     在操作系统的基本概念中进程是程序的一次执行,且是拥有资源的最小单位和调度单位(在引入线程的操作系统中,线程是最小的调度单位)。在Linux系统中创建进程有两种方式:一是由操作系统创建,二是由父进程创建进程(通常为子进程)。系统...

qq_37305092的博客 207

深入理解fork():系统调用创建进程的原理与实践

本文介绍了Unix/Linux系统中的fork()函数,它是创建新进程的核心系统调用。fork()会生成与父进程几乎相同的子进程,采用写时复制(Copy-On-Write)技术实现数据共享与独立。文章详细解析了fork()的基本概念、使用方法和工作原理,包括进程创建机制、代码共享特性以及通过返回值区分父子进程的标准方法。同时提供了典型示例来说明写时复制技术的实际应用场景,并强调了父子进程执行顺序的确定性、资源管理和并发控制等注意事项。这些知识是理解Unix/Linux多进程编程的基础。

祯的博客 1137

fork()和多线程

一、fork()函数     在操作系统的基本概念中进程是程序的一次执行,且是拥有资源的最小单位和调度单位(在引入线程的操作系统中,线程是最小的调度单位)。在Linux系统中创建进程有两种方式:一是由操作系统创建,二是由父进程创建进程(通常为子进程)。系统调用函数fork()是创建一个新进程的唯一方式,当然vfork()也可以创建进程,但是实际上其还是调用了fork()函数。fork()函数

Together_CZ的博客 3984

【深入理解】Linux 中的 fork():一次调用,两次返回的秘密 ✨

作用:复制当前进程(父进程),创建一个新的子进程。返回值父进程:返回子进程的 PID(>0)子进程:返回 0失败:返回 -1(如资源足、进程超限)特性说明哲学理念一次调用,两次返回性能机制写时复制(COW),高效避免冗余内存复制使用建议配合exec(),调用wait(),小心线程场景替代方案vfork()clone()理解fork()的原理和使用技巧,是掌握 Linux 系统编程的必经之路。也可以留言你在使用fork()中遇到的问题或思考!

m0_56508437的博客 2607

muduo库学习之C++多线程系统编程精要06——RAII与fork

东阳的学习笔记 审慎使用 fork() fork()可能会导致资源泄漏 但是,假如程序会fork(),上面的假设就会被破坏了 考虑下面这个例子,Foo对象构造了一次,但是析构了两次 int main() { Foo foo; //调用构造函数 fork(); //fork为两个进程 foo.doit(); //在父子进程中都使用foo //析构函数会被调用两次,父进程和子进程各一次 } 还可能会出现的错误:如果Foo class封装了某种资源,而.

qq_22473333的博客 218

fork函数的注意

fork函数时unix下的以自身进程创建子进程的系统调用,一次调用两次返回,返回为0的是子进程,大于0的是父进程。注意fork调用出,父进程的空间会被原模原样的复制到子进程中,包括指令,变量值,程序调用栈,缓冲区。这里给一个例子 #include <stdio.h> #include <sys/types.h> #include <unistd.h>`int main(void) {

辛明辉的专栏 606

fork()遇上for循环, 使用fork()函数的坑,请你注意!

如果了解什么是fork()函数,欢迎阅读我的另一篇博客 函数可以有两个返回值?初探神奇的fork()函数 warning 1 fork()函数自身保证子进程和父进程的执行顺序 比如当我们执行几次程序就会发现 虽然每次都是先打印父进程,再打印子进程,但是两次父子进程从属关系都发生了改变 先看第一次执行的结果: PID为2236的父进程创建了一个PID为2237的子进程 但...

wck0617 1万+

关于fork()函数需要注意的地方

1.关于fork()的描述 fork通过复制调用进程创建一个新进程,则这个新进程就叫做子进程,被调用的进程叫做父进程。子进程与父进程在同的内存空间中运行。在调用fork()函数时,两个内存空间具有相同内容。其中一个进程执行的内存写、文件映射对另一个进程没有影响。 2.关于fork()返回值 当成功调用fork()时,在父进程中返回子进程的PID,且返回值为0.调用失败时,返回值为-1。如果没有创建新进程时,系统会返回一个非负整数。 3.代码编程实例 编译运行结果如下: ...

qiao代码的木偶人的博客 370

python3.8 进程池 多进程的实现 加速程序运行

进程池 我们使用multiprocessing库下的Pool开启多进程 multiprocessing是python3内置的,需要下载安装,直接导入即可 我们写个简单的实例,来展示到底为什么要使用多进程,以及多进程有哪些作用 让我们使用进程的第一种情况观察 阻塞 from time import sleep from multiprocessing import Pool import os # 引入os库的作用是为了获取子进程的ID,让我们更直观查看进程的进度 def pid():

USADA 4800

汇川触摸屏HMI IT6000系列编程软件InoTouch Editor V2.6.8.zip

汇川触摸屏HMI IT6000系列编程软件InoTouch Editor V2.6.8

上一篇: Protocol Buffer 学习笔记
wind19
博客等级 码龄23年 477粉丝 170原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值