线程中可以创建进程吗_Linux 进程线程是如何创建的?

上文讲了《Linux进程在内核眼中是什么样子的?》,可以理解内核关于进程线程的所有管理就通过一个结构体 —— task_struct。知道了内核眼中进程的描述,本文通过三个例子站在用户态看下进程线程是如何创建的,不同的创建方式又有哪些优劣?

fork例子

先看一个例子:

#include#include#includeint main()      {          pid_t pid;          int cnt = 0;          pid = fork();         if(pid<0)             printf("error in fork!\n");         else if(pid == 0)         {             cnt++;             printf("cnt=%d\n",cnt);             printf("I am the child process,ID is %d\n",getpid());         }         else       {             cnt++;             printf("cnt=%d\n",cnt);             printf("I am the parent process,ID is %d\n",getpid());         }         return 0;   }
运行结果为:
cnt=1I am the parent process,ID is 15247cnt=1I am the child process,ID is 15248
注意,第二个cnt并不是2,为什么会这个结果呢?因为子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。这意味着父子进程间不共享这些存储空间。内核将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。由于在复制时复制了父进程的堆栈段,所以两个进程都停留在fork函数中,等待返回。因此fork函数会返回两次,一次是在父进程中返回,另一次是在子进程中返回,这两次的返回值是不一样的。

调用fork之后,数据、堆栈有两份,但是代码段仍然为一份,这个代码段是两个进程的共享代码段,都从fork函数中返回。当父子进程有一个想要修改数据或者堆栈时,两个进程真正分裂。

fork有两个特点:
  • “调用一次,返回两次”,在父进程中调用一次,在父进程和子进程中各返回一次。
  • 所有由父进程打开的描述符都被复制到子进程中。父、子进程中相同编号的文件描述符在内核中指向同一个file结构体,也就是说,file结构体的引用计数要增加。

vfork例子

把上面程序中的fork改成vfork,运行结果是什么样子的呢?

cnt=1I am the child process,ID is 15385cnt=-486109114I am the parent process,ID is 15384a.out: cxa_atexit.c:100: __new_exitfn: Assertion `l != NULL' failed.Aborted (core dumped)
咦?为什么会有段错误?这是因为没有调用exec函数,vfork()保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行。我们把上面的程序修改如下:
#include#include#includeint main()      {         pid_t pid;          int cnt = 0;         pid = vfork();         if(pid<0)            printf("error in fork!\n");        else if(pid == 0)         {             cnt++;             printf("cnt=%d\n",cnt);             printf("I am the child process,ID is %d\n",getpid());            _exit(0);         }         else       {             cnt++;             printf("cnt=%d\n",cnt);             printf("I am the parent process,ID is %d\n",getpid());         }         return 0;     }
运行结果如下:
cnt=1I am the child process,ID is 15524cnt=2I am the parent process,ID is 15523
可见成功执行了,并且cnt是2。因为调用了exec,使得子进程退出,父进程执行,这样else 后的语句就会被父进程执行,又因在子进程调用exec或exit之前与父进程数据是共享的, 所以子进程退出后把父进程的数据段count改成1 了,子进程退出后,父进程又执行,最终就将cnt变成了2。

fork 和 vfork的一些思考

根据上面的例子我们知道 fork 和 vfork 各有优劣,可以用下图大概描述。

9915b1f597e78225e9deed35465e2893.png

图片来自网络fork 要多拷贝一次内存,vfork 用起来又麻烦而且有风险,讲真,并不鼓励用 vfork。那么有没有办法对 fork 做个优化,答案是肯定的。目前内核对 fork 做了写时拷贝(COW)的优化。也就是说,对于fork后并不是立马拷贝内存,而是只有你在需要改变的时候,才会从父进程中拷贝到子进程中,这样fork 后立马执行 exec 的成本就非常小了。

clone 创建线程

现在我们知道了创建进程有两种方式:fork,vfork。那么创建线程呢?

首先得知道什么是进程,什么是线程。有句名言 “进程是资源管理的最小单位,线程是程序执行的最小单位。” 在操作系统设计上,从进程演化出线程,最主要的目的就是减小多进程上下文切换开销。

因此进程之间共享代码段,文件描述符,信号处理,全局变量等的话就称为线程,如果不共享,就是我们所说的进程。

38df4d0bd97cf7855a87be7ee092e5f4.png

线程的创建接口是用 clone,或者经常用的 pthread_create。

进程线程创建总图

我们先站在上帝视角以一张图来看下进程线程创建的大体框架,具体的实现下文见。

bdef9a9e083b0be7b0f3e246907fe723.png


7de66a6648422023aaa88bf60d7ef106.png

添加极客助手微信,加入技术交流群

cda2cb7a524e23f156f46288da9165fa.png

c23e0fdf0a71d86144846dad971748b9.png

长按,扫码,关注公众号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555932.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

http请求发生了两次(options请求)

前言 自后台restful接口流行开来&#xff0c;请求了两次的情况&#xff08;options请求&#xff09;越来越普遍。笔者也在实际的项目中遇到过这种情况&#xff0c;做一下整理总结。 文章书写思路&#xff1a; 为什么发生两次请求 http的请求方式&#xff0c;包括OPTIONS、GET…

servlet怎么接受请求_谁再问Servlet的问题,我就亲自上门来教学了

1. 概述在这篇简短的文章中&#xff0c;我们将从概念上理解什么是servlet 和 servlet 容器以及它们是如何工作的。同时&#xff0c;还能在请求、响应、会话对象、共享变量和多线程的上下文中看到它们的身影。2. Servlets 和 它的容器servlet 是 JEE 用于 web 开发常用的组件。它…

pythonwebui自动化_python+selenium实现web端UI自动化测试

代码示例&#xff1a;css#!/usr/bin/python# -*- coding: UTF-8 -*-# coding:utf8import sysimport osfrom selenium import webdriversys.path.append(os.getcwd())driver webdriver.Chrome(/Users/fyh/tool/chromedriver) # Optional argument, if not specified will searc…

Mysql中SQL语句不使用索引的情况

Mysql中SQL语句不使用索引的情况 MySQL查询不使用索引汇总 众所周知&#xff0c;增加索引是提高查询速度的有效途径&#xff0c;但是很多时候&#xff0c;即使增加了索引&#xff0c;查询仍然不使用索引&#xff0c;这种情况严重影响性能&#xff0c;这里就简单总结几条MySQL…

redis python 出错重连_python穿透类 对象代理

# coding:utf-8import osimport logging# 对象代理# 用于解决需要在包调用与业务代码之间增加一些其他操作的场景# 比如&#xff1a;应用程序中使用redis包对象&#xff0c;我们希望在redis包对象出错时尝试一次重连# 又比如: 我们希望在调用包的某方法时纪录日志# 使用此代理容…

详解mysql什么时候不走索引

全值匹配我最爱&#xff0c;最左前缀要遵守&#xff1b; 带头大哥不能死&#xff0c;中间兄弟不能断&#xff1b; 索引列上不计算&#xff0c;范围之后全失效&#xff1b; LIKE百分写最右&#xff0c;覆盖索引不写 *&#xff1b; 不等空值还有or&#xff0c;索引失效要少用&…

unbuntu cmake安装mysql_ubuntu下编译安装mysql5.5

1.主要步骤如下添加mysql用户和用户组—>下载源码—>解压源码安装编译2个套件—>编译源码-安装编译好的程序-配置mysql启动服务2.Mysql源码解压建好相应的安装目录&#xff0c;将压缩文件复制到安装目录并解压。3.添加用户组Sudo groupadd mysql4.添加用户Sudo userad…

MYSQL中数据类型介绍

一、MySQL的数据类型 主要包括以下五大类&#xff1a; 整数类型&#xff1a;BIT、BOOL、TINY INT、SMALL INT、MEDIUM INT、 INT、 BIG INT 浮点数类型&#xff1a;FLOAT、DOUBLE、DECIMAL 字符串类型&#xff1a;CHAR、VARCHAR、TINY TEXT、TEXT、MEDIUM TEXT、LONGTEXT、…

mysql删库后恢复_记一次MySQL删库的数据恢复

昨天因为不可描述的原因&#xff0c;数据库直接被 drop database删除。在第一时间停止数据库服务和Web服务&#xff0c;备份MySQL数据目录下的所有文件之后&#xff0c;开始走上数据恢复之路。第一次干这种事&#xff0c;各种不得法。因为我们既没有备份&#xff0c;也没有开启…

mysql中数据类型的长度

一、varchar&#xff08;n&#xff09;、char(n)中的n的含义 1&#xff09;varchar(m),char(n)里面的m或n代表的是字符的个数。 打开mysql手册&#xff0c;看到这样一句话 The CHAR and VARCHAR types are declared with a length that indicates the maximum number of char…

mysql数据库操作宠物表_mysql数据库之表的操作

语法&#xff1a;1. 修改表名ALTER TABLE 表名RENAME 新表名;2. 增加字段ALTER TABLE 表名ADD 字段名 数据类型 [完整性约束条件…],ADD 字段名 数据类型 [完整性约束条件…];ALTER TABLE 表名ADD 字段名 数据类型 [完整性约束条件…] FIRST;ALTER TABLE 表名ADD 字段名 数据类…

Mysql 中的Text字段的范围

Mysql 中的Text字段的范围 text&#xff1a;存储可变长度的非Unicode数据&#xff0c;最大长度为2^31-1个字符。text列不能有默认值&#xff0c;存储或检索过程中&#xff0c;不存在大小写转换&#xff0c;后面如果指定长度&#xff0c;不会报错误&#xff0c;但是这个长度是不…

python实现语义分割_语义分割算法之FCN论文阅读及源码实现

论文原文创新点提出了一种端到端的做语义分割的方法&#xff0c;在这里插入图片描述如图&#xff0c;直接拿分割的ground truth作为监督信息&#xff0c;训练一个端到端的网络&#xff0c;让网络做p像素级别的预测。如何设计网络结构如何做像素级别的预测在这里插入图片描述在V…

记住:永远不要在MySQL中使用“utf8”,请使用“utf8mb4” 程序员

记住&#xff1a;永远不要在MySQL中使用“utf8”&#xff0c;请使用“utf8mb4” 最近我遇到了一个bug&#xff0c;我试着通过Rails在以“utf8”编码的MariaDB中保存一个UTF-8字符串&#xff0c;然后出现了一个离奇的错误&#xff1a; 我用的是UTF-8编码的客户端&#xff0c;服…

mysql——decimal类型与decimal长度

分为三种&#xff1a; float&#xff1a;浮点型&#xff0c;含字节数为4&#xff0c;32bit&#xff0c;数值范围为-3.4E38~3.4E38&#xff08;7个有效位&#xff09;double&#xff1a;双精度实型&#xff0c;含字节数为8&#xff0c;64bit&#xff0c;数值范围-1.7E308~1.7E3…

右上角的引用文献格式_论文要引用的小符号右上角怎么打?

上标是【现在】论【文的】书写【都会】【用到】引用【的小】符号&#xff0c;上标【一般】用【来对】所标的【文字】【或者】段落【进行】进【一步】【的解】释&#xff0c;【所以】常【用来】【解释】含义&#xff0c;【或者】出处&#xff0c;【而其】【解释】【一般】在书【…

java.util.function.Function的用法

JDK 1.8 API包含了很多内建的函数式接口&#xff0c;在老Java中常用到的比如Comparator或者Runnable接口&#xff0c;这些接口都增加了FunctionalInterface注解以便能用在lambda上。现如今&#xff0c;我们则从Function常用函数入口&#xff0c;真正了解一下。 nametypedescri…

mysql服务器程序_MySQL服务器

1、安装通常系统在成功安装之后就已经自带MySQL服务器以及客户端了。查询MySQL及其相关文件是否安装&#xff1a;rpm -qa | grep perlrpm -qa | grep mysql如果没有安装&#xff0c;则可以使用yum进行安装&#xff1a;yum -y install perl-DBIyum -y install perl-DBD-MySQLyum…

Java中List的contains方法,你用对了吗?

Java语言中的List是我们处理集合时经常会用到的。而List定义了一个contains方法&#xff0c;用以判断一个集合中是否包含指定的一个对象。 大家应该有用到过吧&#xff0c;可是你真的会用&#xff0c;用对了吗&#xff1f; 看看下面的代码。 上图代码中&#xff0c;创建了两个…

mysql sql in or 替换_sql IN 的用法一例--替换 mysql longtext字段中某些内容的用法

之前给改版的一个学校里的站点突然提出要求&#xff0c;说需要将之前编辑的文章的字体大小全部改成默认值。字体的控制无非有两种&#xff0c;一是font-size 16 px&#xff1b;然后是。但是&#xff0c;之前发布的文章&#xff0c;文字的控制是由编辑器生成的&#xff0c;而根…