《Linux C编程实战》笔记:进程操作之创建进程

进程是一个动态的实体,是程序的一次执行过程。进程是操作系统资源分配的基本单位。

以下是一些概念,我就直接抄书了

进程是操作系统的知识,简单理解的话,你写的代码运行起来算一个进程?

创建进程

每个进程由进程ID号标识,进程被创建时系统会为其分配一个惟一的进程ID。当一个进程向其父进程(创建该进程的进程)传递其终止消息时,意味这个进程的整个生命周期的结束。此时,该进程占用的所有资源包括进程ID被全部释放。
创建进程有两种方式,一是由操作系统创建;二是由父进程创建。由操作系统创建的进程,它们之间是平等的,一般不存在资源继承关系。而对于由父进程创建的进程(通常称为子进程),它们和父进程存在隶属关系。子进程又可以创建进程,这样形成一个进程家族。子进程可以继承其父进程几乎所有的资源。在系统启动时,操作系统会创建一些进程,它们承担着管理和分配系统资源的任务,这些进程通常被称为系统进程。
系统调用fork是创建一个新进程的惟一方法(创建一个进程通常也称为fork一个进程),除了极少数以特殊方式创建的进程,如 init进程,它是内核启动时以特殊方式创建的。进程调用fork函数就创建了一个子进程。
创建了一个子进程之后,父进程和子进程争夺CPU,抢到CPU 者执行,另外一个挂起等待。如果想要父进程等待子进程执行完毕以后再继续执行,可以在 fork 操作之后调用 wait或waitpid。一个刚刚被fork的子进程会和它的父进程一样,继续执行当前的程序。几个进程同时执行一个应用程序通常用处不大。更常见的使用方法是子进程在被fork后可以通过调用exec函数执行其他程序

fork函数

#include<sys/types.h>
#include<unistd.h>
pid_t fork(void);

一般情况下,函数最多有一个返回值,但fork函数非常特殊,它有两个返回值,即调用一次返回两次。成功调用fork函数后,当前进程实际上已经分裂为两个进程,一个是原来的父进程,另一个是刚刚创建的子进程。父子进程在调用fork函数的地方分开,fork函数有两个返回值,一个是父进程调用fork函数后的返回值,该返回值是刚刚创建的子进程的ID;另一个是子进程中fork函数的返回值,该返回值是0。fork函数返回两次的前提是进程创建成功,如果进程创建失败,则只返回-1。两次返回不同的值,子进程返回值为0,而父进程的返回值为新创建的子进程的进程ID,这样可以用返回值来区别父、子进程。

示例程序1

演示fork函数的用法

#include<cstdlib>
#include<cstring>
#include <cstdio>
#include<ctime>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<cerrno>
using namespace std;int main(){pid_t pid;printf("Process creation study\n");pid=fork();//创建子进程switch (pid){case 0://子进程printf("Child process is running,CurPid is %d,ParentPid is %d\n",pid,getppid());break;case -1://创建失败perror("Process creation failed\n");break;default://父进程printf("Parent process is running,ChildPid is %d,ParentPid is %d\n",pid,getpid());break;}exit(0);
}

运行结果

可以看到,fork在父子进程的返回值不同。程序在fork执行完后在此处创建一个子进程,父子进程会分别一起执行fork之后的语句。

结果里是父进程先于子进程执行,但一般来说是不固定的

示例程序2

为了演示这种不固定,可以看以下示例程序

#include<cstdlib>
#include<cstring>
#include <cstdio>
#include<ctime>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<cerrno>
using namespace std;int main(){pid_t pid;const char *msg;int k;printf("Process creation study\n");pid=fork();switch (pid){case 0:msg="Child process is running\n";//子进程会输出的字符串k=3;break;case -1:perror("Process creation failed\n");break;default:msg="Parent process is running\n";//父进程会输出的字符串k=5;break;}while (k>0){fputs(msg,stdout);sleep(1);k--;//子进程和父进程的k不相同}exit(0);
}

运行结果:

可以看出父子进程交替执行

sleep() 函数是一个标准C库函数,用于让程序暂停执行指定的时间,以秒为单位。在Linux/Unix系统中,它的声明在头文件 <unistd.h> 中。

前面提到 fork在创建进程失败时,返回-1。失败的原因通常是父进程拥有的子进程的个数超过了规定的限制,此时errno值为EAGAIN。如果可供使用的内存不足也会导致进程创建失败,此时errno值为 ENOMEM

子进程会继承父进程的很多属性,主要包括用户ID、组ID、当前工作目录、根目录、打开的文件、创建文件时使用的屏蔽字、信号屏蔽字、上下文环境、共享的存储段、资源限制等。子进程与父进程有一些不同的属性,主要有如下这些。

  1. 子进程有它自己惟一的进程ID。
  2. fork的返回值不同,父进程返回子进程的ID,子进程的则为0。
  3. 不同的父进程ID。子进程的受进程D为创建它的父进程ID。
  4. 子进程共享父进程打开的文件描述符,但父进程对文件描述符的改变不会影响子进程中的文件描述符。
  5. 子进程不继承父进程设置的文件锁。
  6. 子进程不继承父进程设置的警告。
  7. 子进程的未决信号集被清空。

示例程序3

本示例演示孤儿进程

如果一个子进程的父进程先于子进程结束,子进程就成为一个孤儿进程,它由 init进程收养,成为init进程的子进程。

#include<cstdlib>
#include<cstring>
#include <cstdio>
#include<ctime>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<cerrno>
using namespace std;
int main(){pid_t pid;pid=fork();switch (pid){case 0://子进程进入一个死循环,一直不会结束while (1){printf("A background process,PID:%d\n,ParentID:%d\n",getpid(),getppid());sleep(3);}case -1:perror("Process creation failed\n");exit(-1);default://父进程先结束printf("I am parent process,my pid is %d\n",getpid());exit(0);}   return 0;
}

这我就不运行了,子进程根本结束不了,预期的运行结果是这样的

父进程打印一次就执行完毕了,此后子进程就成了孤儿进程,由init进程收养,可以看到此时子进程的父进程ID变为1.

vfork函数

vfork也可以用来创建新进程,和fork相比,他有独特用处。

  1. 返回值:

    • fork() 的返回值是新创建的子进程的进程ID(PID)在父进程中,而在子进程中返回0。因此,通过返回值的不同可以在父进程和子进程中采取不同的操作。
    • vfork() 的返回值也是新创建的子进程的PID,但与fork() 不同的是,父进程和子进程共享地址空间,所以在子进程中对地址空间的修改会影响到父进程。
  2. 地址空间:

    • fork() 中,子进程获得父进程的完整地址空间的副本,父子进程互不干扰,各自独立执行。
    • vfork() 中,子进程共享父进程的地址空间,子进程运行在父进程的地址空间中,直到调用 exec 函数或者 exit()
  3. 执行时机:

    • fork() 中,父进程和子进程之间的执行是并发的,即它们可以同时运行。
    • vfork() 中,父进程会被挂起,直到子进程调用 exec 函数或者 exit(),因为子进程共享父进程的地址空间,如果父进程继续执行可能会影响到子进程的执行。
  4. 用途:

    • fork() 适用于创建一个独立的进程,父子进程各自执行,相互不影响。通常用于多任务并发执行。
    • vfork() 主要设计用于在子进程中立即执行一个新程序,它更加轻量级,因为不需要复制整个地址空间,但是需要小心使用,以避免父子进程之间的竞态条件。

总体而言,fork() 适用于大多数常规情况,而 vfork() 更适用于特殊情况,例如在子进程中立即执行一个新程序,而不涉及大量的地址空间复制。

简单来说,vfork创建的子进程会先执行,执行完毕父进程才能继续,而且子进程对变量的修改父进程可见且受影响,因为它们共享地址空间。

使用vfork需谨慎。

示例程序4

下面例子说明两者的不同

#include<cstdlib>
#include<cstring>
#include <cstdio>
#include<ctime>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<cerrno>
using namespace std;
int globVar=5;//全局变量int main(){pid_t pid;int var=1,i;pid=fork();/*pid=vfork();*/switch (pid){case 0:i=3;while (i-->0){printf("Child process is running\n");globVar++;var++;sleep(1);}printf("Child's globVar =%d,var=%d\n",globVar,var);break;case -1:perror("Process creation failed\n");exit(-1);default:i=5;while (i-->0){printf("Parent process is running\n");globVar++;var++;sleep(1);}printf("Parent's globVar =%d,var=%d\n",globVar,var);break;}   exit(0);
}

首先我们运行fork版本的

可以看到子进程和父进程不管是全局的globvar还是局部的var都增加了对应的值,证明子父进程地址空间是独立的。而且子父进程的执行顺序不确定。

下面我们把fork注释,把vfork取消注释,再次运行

可以看到父进程结束时的var的值均是在子进程结束时的基础上加的5,证明它们共享地址空间。而且子进程执行完毕后父进程才能继续执行。

书内还有守护进程的内容,不过感觉 跨度有点大,就先跳过了

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

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

相关文章

GPT-4.5!!!

GPT-4 还没用明白&#xff0c;GPT-4.5 就要发布了。 最近&#xff0c;OpenAI 泄露了 GPT-4.5 的发布页面&#xff0c;除了进一步增强复杂推理和跨模态理解&#xff0c;GPT-4.5 增加了一个更加强大的功能——3D。 3D 功能的进一步支持&#xff0c;也就意味着多模态最后一块版图…

关于前端学习的思考-浮动元素嵌套块级元素12.18

1、块级元素嵌套浮动元素 先摆图片&#xff0c;当橘色的盒子高度减少的时候&#xff0c;NK AD TB PK NN并不会减少。如何解决呢&#xff1f; 加一个overflow&#xff1a;clip或者hidden 2、浮动元素嵌套块级元素 加一个overflow&#xff1a;clip或者hidden 综上所述&#xff0…

giee 添加公匙 流程记录

一、安装 百度网盘CSDN4文件夹下&#xff0c;或者官网下载&#xff1a;https://git-scm.com/downloads 二、生成密钥 1.右击打开git bash 2.$ ssh-keygen -t rsa -C “个人邮箱地址”&#xff0c;按3个回车&#xff0c;密码为空。 3.在C:\Users{windows用户名}.ssh目录下得到…

[Ray Tracing in One Weekend] 笔记

前言 本文参照自raytracing in one weekend教程&#xff0c;地址为&#xff1a;https://raytracing.github.io/books/RayTracingInOneWeekend.html 什么是光线追踪&#xff1f; 光线追踪模拟现实中的成像原理&#xff0c;通过模拟一条条直线在场景内反射折射&#xff0c;最终…

算法——分治

思想&#xff1a;分而治之&#xff0c;将大问题转化为若干个相同或相似的子问题。快排的题目常见的方法是利用三指针法将数组分三块搭配随机选择基准元素的思想 颜色分类&#xff08;分治_快排&#xff09; 颜色分类 题目解析 原地对它们进行排序&#xff0c;使得相同颜色的元…

Oracle-应用会话集中在RAC集群一个节点问题

问题&#xff1a; 用户一套Oracle19c RAC集群&#xff0c;出现一个奇怪的现象&#xff0c;通过SCAN IP访问的连接会话都集中在节点一实例&#xff0c;而且用户并没有做任何的节点服务访问去控制会话的连接节点&#xff0c;比如常见的通过集群的高可用服务去控制应用访问连接集中…

Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)

目录 一、前言 二、基于注解配置Bean 1.基本介绍 : 2.应用实例 : 3.注意事项 : 三、手动实现Spring 注解配置机制 1.需求 : 2.思路 : 3.实现 : 3.1 自定义注解类 3.2 自定义配置类 3.3 自定义容器类 3.4 在测试类中进行测试 四、自动装配 0.总述 : 1.AutoWired自动装…

LeetCode力扣每日一题(Java):69、x 的平方根

一、题目 二、解题思路 1、 我的思路 我的思路是直接循环暴力破解&#xff0c;定义计数器i&#xff0c;从1开始递增&#xff0c;直到i*i大于或等于x 于是有了如下代码 int i 1;while(true){if(i*i<x){i;}else if(i*ix){return i;}else{return i-1;}} 但提交之后超出了…

亚马逊、target、eBay、沃尔玛等平台采退、下卡,技术技巧大揭秘

今天想和大家分享一些关于做测评、采退和撸卡项目时所需的防关联和防封号环境的底层技术原理。这些内容相对比较复杂&#xff0c;相信很少有人能够完全掌握&#xff0c;因为涉及到一些比较高级的IT技术原理。 如果正在考虑开始做采退或者撸卡项目&#xff0c;或者已经在进行相…

libxls - 编译

文章目录 libxls - 编译概述笔记静态库工程测试控制台exe工程测试备注备注END libxls - 编译 概述 想处理.xls格式的excel文件. 查了一下libxls库可以干这个事. 库地址 https://github.com/libxls/libxls.git 但是这个库的makefile写的有问题, 在mingw和WSL下都编译不了. 好在…

高德地图绘制区域的地理围栏

官网示例 https://lbs.amap.com/demo/javascript-api-v2/example/overlayers/polygon-draw/ <!doctype html> <html> <head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta …

黑马点评06分布式锁 2Redisson

实战篇-17.分布式锁-Redisson功能介绍_哔哩哔哩_bilibili 1.还存在的问题 直接实现很麻烦&#xff0c;借鉴已有的框架。 2.Redisson用法 3.Redisson可重入原理 在获取锁的时候&#xff0c;看看申请的线程和拿锁的线程是否一致&#xff0c;然后计算该线程获取锁的次数。一个方法…

爬虫chrome浏览器抓包说明

chrome浏览器抓包说明 目标&#xff1a;掌握chrome在爬虫中的使用 1. 新建隐身窗口&#xff08;无痕窗口&#xff09; 作用&#xff1a;在打开无痕窗口的时候&#xff0c;第一次请求某个网站是没有携带cookie的&#xff0c;和代码请求一个网站一样&#xff0c;这样就能够尽可…

堆与二叉树(上)

本篇主要讲的是一些概念&#xff0c;推论和堆的实现&#xff08;核心在堆的实现这一块&#xff09; 涉及到的一些结论&#xff0c;证明放到最后&#xff0c;可以选择跳过&#xff0c;知识点过多&#xff0c;当复习一用差不多&#xff0c;如果是刚学这一块的&#xff0c;建议打…

爬虫练习-获取imooc课程目录

代码&#xff1a; from bs4 import BeautifulSoup import requests headers{ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0, }id371 #课程id htmlrequests.get(https://coding.imooc.com/class/chapter/id.html#Anchor,head…

实验三 MapReduce编程

实验目的&#xff1a; 1.掌握MapReduce的基本编程流程&#xff1b; 2.掌握MapReduce序列化的使用&#xff1b; 实验内容&#xff1a; 一、在本地创建名为MapReduceTest的Maven工程&#xff0c;在pom.xml中引入相关依赖包&#xff0c;配置log4j.properties文件&#xff0c;搭…

软信天成:产品信息管理(PIM)对零售行业有何意义?

产品信息管理&#xff08;PIM&#xff09;&#xff0c;通过快速收集、管理和共享横跨整个企业、合作伙伴和供应商的产品信息&#xff0c;整合分散在不同系统或部门的数据信息&#xff0c;创建实时、可信的产品数据源&#xff0c;及时获取整个企业详细、准确和一致的产品信息&am…

前端做表格导出

下面来介绍一下方法 在vue页面里写调用方法 //表头数据格式 column: [{ key: Photo, width: 70, height: 50, colWidth: 100, title: 图片, type: image },{ key: Name, colWidth: , title: 名称, type: text },{ key: Phone, colWidth: , title: 手机号, type: text },{key:…

使用Log4j与log4j2配置mybatisplus打印sql日志

环境&#xff1a;项目非完全spring项目&#xff0c;没有spring的配置文件。执行sql时老是不打印sql语句。因此进行修改&#xff0c;过程比较坎坷&#xff0c;记录一下。 我尝试使用log4j和log4j2进行配置 最终把这两种全部配置记录上 Log4j配置 如果项目用的是log4j需要进行配置…

【✅如何针对大Excel做文件读取?】

✅如何针对大Excel做文件读取&#xff1f; &#x1f7e9;如何针对大Excel做文件读取&#x1f7e9;XSSFWorkbook文件读取&#x1f7e9;EasyExcel文件读取 ✅扩展知识&#x1f7e9; EasyExcel简介&#x1f7e9;EasyExcel 为什么内存占用小&#xff1f; &#x1f7e9;如何针对大Ex…