Linux系统编程---进程(一)

一、进程的相关概念

进程和程序:

我们平时写好的代码,通过编译后生成的可执行文件就是一个程序,不占用系统资源(cpu、内存、打开的文件、设备、锁....),当这个程序被运行起来后(没结束之前) 它就成为了一个进程,进程是活跃的程序,占用系统资源,在内存中执行

程序:静态的,即死的。只占用磁盘空间。 ——剧本

进程:动态的,即活的。运行起来的程序。占用内存、cpu等系统资源。 ——戏

进程的状态:

在三态模型中,进程状态分为三个基本状态,即:运行态、就绪态、阻塞态

在五态模型中,进程状态分为五个基本状态,即:初始态、就绪态、运行态、挂起态、终止态

其中初始态为进程准备阶段,常与就绪态结合来看。

PCB进程控制块: 

进程id

文件描述符表

进程状态: 初始态、就绪态、运行态、挂起态、终止态。

进程工作目录位置

*umask掩码 (进程的概念)

信号相关信息资源。

用户id和组id

ps aux 返回结果里,第二列是进程id 

环境变量:

echo $PATH 查看环境变量

path环境变量里记录了一系列的值,当运行一个可执行文件时,系统会去环境变量记录的位置里查找这个文件并执行。

echo $TERM 查看终端

echo $LANG 查看语言

env 查看所有环境变量

二、进程控制

1. fork创建子进程

系统允许一个进程创建新进程,新进程即为子进程,子进程还可以创建新的子进程,形成进程树结构模型。

fork函数原理:

fork之前的代码,父子进程都有,但是只有父进程执行了,子进程没有执行,fork之后的代码,父子进程都有机会执行。

pid_t fork(void);

功能:

用于从一个已存在的进程中创建一个新进程,新进程称为子进程,原进程称为父进程。子进程是父进程的一个几乎完全独立的副本,包括内存空间、文件描述符、环境变量等,子进程获得的是这些资源的复制品,所以原进程和新进程的资源是相互独立的

参数:

        无

返回值:

        成功:子进程中返回0,父进程中返回子进程ID(PID)

        失败:返回-1
失败原因:
        通常是因为系统级别错误(如可用进程数量达到限制)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>int main(int argc,char *argv[])
{printf("before fork-1-\n");printf("before fork-2-\n");printf("before fork-3-\n");printf("before fork-4-\n");pid_t pid = fork();if (pid == -1){perror("fork error");exit(1);}else if(pid == 0){printf("---child is created\n");}else if(pid > 0){printf("---parent process:my child is %d\n",pid);}printf("============end of file\n");return 0;
}

输出如下:

before fork-1-
before fork-2-
before fork-3-
before fork-4-
---parent process:my child is 2332517
============end of file
---child is created
============end of file

循环创建多个子进程:

        通过命令行参数指定创建进程的个数,每个进程休眠1S打印自己是第几个被创建的进程。如:第1个子进程休眠0秒打印:“我是第1个子进程”;第2个进程休眠1秒打印:“我是第2个子进程”;第3个进程休眠2秒打印:“我是第3个子进程”。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>int main(int argc,char *argv[])
{int i;pid_t pid;for (i = 0;i < 5;i++){  if (fork() == 0)   //循环期间,子进程不forkbreak;}if (5 == i){    sleep(5);printf("I'm parent\n");}else{        sleep(i);printf("I'm %dth child\n",i+1);}return 0;
}

输出如下:

I'm 1th child
I'm 2th child
I'm 3th child
I'm 4th child
I'm 5th child
I'm parent

2. getpid和getppid 

每个进程都由一个进程号来标识,其类型为pid,进程号的范围:0~32767,进程号总是唯一的,但进程号可以重用,当一个进程终止后其进程号就可以再次使用;

进程号(PID):标识进程的一个非负整形数

父进程号(PPID):任何进程都是由另一个进程创建,该进程称为被创建进程的父进程,对应的进程号称为父进程号(PPID),如 A进程创建了B进程,A的进程号就是B进程的父进程号

进程组号(PGID):进程组是一个或多个进程的集合,它们之间相互关联,进程组可以接收同一终端的各种信号,关联的进程有一个进程组号(PGID),默认情况下 当前的进程号会当作当前的进程组号

pid_t getpid(void);

功能:
        获取当前进程号(PID)

参数:
        无

返回值:
        本进程号

pid_t getppid(void);        获取当前进程的父进程ID

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>int main(int argc,char *argv[])
{printf("before fork-1-\n");//在fork之前打印,父进程执行,只执行一次printf("before fork-2-\n");printf("before fork-3-\n");printf("before fork-4-\n");pid_t pid = fork();//创建子进程if (pid == -1){perror("fork error");exit(1);}else if(pid == 0){     //子进程printf("---child is created,pid=%d,parent-pid:%d\n",getpid(),getppid());}else if(pid > 0){      //父进程printf("---parent process:my child is %d,my pid:%d,my parent pid:%d\n",pid,getpid(),getppid());}printf("============end of file\n");//父子进程各执行一次return 0;
}

 输出如下:

before fork-1-
before fork-2-
before fork-3-
before fork-4-
---parent process:my child is 2328447,my pid:2328446,my parent pid:2272084
============end of file
---child is created,pid=2328447,parent-pid:2328446
============end of file

父进程先结束,导致子进程成孤儿,于是回收到孤儿院,看起来合情合理。

修改一下代码,给父进程增加一个等待命令,这样能保证子进程完成时,父进程处于执行状态,子进程就不会成孤儿。同时,这里也解决了终端提示符和输出混在一起的问题。代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>int main(int argc,char *argv[])
{printf("before fork-1-\n");//在fork之前打印,父进程执行,只执行一次printf("before fork-2-\n");printf("before fork-3-\n");printf("before fork-4-\n");pid_t pid = fork();//创建子进程if (pid == -1){perror("fork error");exit(1);}else if(pid == 0){     //子进程printf("---child is created,pid=%d,parent-pid:%d\n",getpid(),getppid());}else if(pid > 0){      //父进程sleep(1);printf("---parent process:my child is %d,my pid:%d,my parent pid:%d\n",pid,getpid(),getppid());}printf("============end of file\n");//父子进程各执行一次return 0;
}

输出如下:

before fork-1-
before fork-2-
before fork-3-
before fork-4-
---child is created,pid=2338015,parent-pid:2338014
============end of file
---parent process:my child is 2338015,my pid:2338014,my parent pid:2272084
============end of file

 三、进程共享

父子进程之间在fork后共享哪些内容:

父子进程相同:

全局变量、data段、text段、栈、堆、环境变量、用户ID、宿主目录、进程工作目录、信号处理方式

父子进程不同:

进程ID、fork返回值、父进程ID、进程运行时间、闹钟(定时器)、未决信号集

父子进程共享:

读时共享、写时复制  ----------------- 全局变量

1.文件描述符(打开文件的结构体) 2. mmap映射区(进程间通信)

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>int var = 100;int main(int argc,char* argv[])
{pid_t pid;pid = fork();if (pid == -1){perror("fork error");exit(1);}else if (pid > 0){var = 288;printf("parent, var = %d\n",var);printf("I'm parent pid = %d,getpid = %d\n",getpid(),getppid());}else if(pid == 0){var = 200;printf("I'm child pid = %d,ppid = %d\n",getpid(),getppid());printf("child,var = %d\n",var);}printf("------------finish-------------\n");return 0;
}

 输出如下:写时复制

parent, var = 288
I'm parent pid = 2348490,getpid = 2272084
------------finish-------------
I'm child pid = 2348491,ppid = 2348490
child,var = 200
------------finish-------------

将var = 200进行注释,输出如下: 读时共享

parent, var = 288
I'm parent pid = 2350816,getpid = 2272084
------------finish-------------
I'm child pid = 2350817,ppid = 2350816
child,var = 100
------------finish-------------

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

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

相关文章

OpenAI开设首个亚洲办公室,定制GPT-4模型Token成本降低47%|TodayAI

OpenAI今日宣布&#xff0c;在日本东京设立新办公室&#xff0c;标志着该公司在亚洲市场的正式扩展。东京作为全球科技领域的领导者&#xff0c;其独特的服务文化和创新社区&#xff0c;是OpenAI选择作为亚洲第一站的理想地点。公司致力于与日本政府、当地企业和研究机构合作&a…

JavaWeb开发03-Mybatis入门-基础操作-XML映射文件-动态SQL

一、Mybatis-入门 Java程序控制数据库 1.入门 定义实体类&#xff1a;一定要和表中的字段一一对应 配置连接数据库数据 建立Mapper层语句&#xff0c;来获取数据库数据以及将其封装到user的list中去。 2.配置SQL提示 为了进行查询数据库中有哪些表&#xff0c;所以得连接数据…

宝宝餐椅上亚马逊美国站要求什么认证?

大家都知道儿童餐椅是宝宝饮食的重要伙伴。它们为宝宝提供了一个舒适的环境&#xff0c;让宝宝在吃饭的时候更愉快&#xff0c;更健康。然而&#xff0c;许多家长可能不知道&#xff0c;亚马逊美国站售卖的儿童餐椅需要进行一系列严格的认证&#xff0c;以保护我们宝贝们的安全…

视频国标学习

总体介绍 GB/T28181协议&#xff0c;全名叫《安全防范视频监控联网系统信息传输、交换、控制技术要求》&#xff0c;是由中国国家标准委员会发布的一种国家级的标准。它主要对视频监控系统的各个方面做了明确的规定&#xff0c;使得不同厂商生产的视频监控设备能够相互连通&am…

Linux学习-数据库

数据库软件: 关系型数据库: Mysql Oracle SqlServer Sqlite 非关系型数据库&#xff1a; Redis NoSQL 1.数组、链表、文件、数据库 数组、链表: 内存存放数据的方式(代码运行结束、关机数据丢失) 文件、…

防范“AI换脸”风险 ZOLOZ Deeper问世

4 月 16 日&#xff0c;深度伪造&#xff08;Deepfake&#xff09;综合防控产品ZOLOZ Deeper 在北京正式发布&#xff0c;以拦截用户刷脸过程中的“AI换脸”风险&#xff0c;目前已率先应用在身份安全领域。公开资料显示&#xff0c;ZOLOZ是蚂蚁数科的科技品牌&#xff0c;以生…

ClickHouse--18--argMin() 和argMax()函数

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 argMin() 和argMax()函数业务场景使用案例1.准备表和数据&#xff1a;业务场景一&#xff1a;查看salary 最高和最小的user业务场景二&#xff1a;根据更新时间获取…

学习经验分享【32】本科/硕士开题报告、中期报告等写作经验分享

本科/硕士阶段首先就是要写开题报告&#xff0c;然后中期报告&#xff0c;这篇博文就是分享一下写报告的经验&#xff0c;避免被老师打回来。本人有丰富的写报告经验&#xff0c;有需要的朋友可添加文末联系方式与我联系。 一、本科开题报告的提纲 课题来源及研究的目的和意义…

lua学习笔记21完结篇(lua中的垃圾回收)

print("*****************************lua中的垃圾回收*******************************") text{id24,name"仙贝"} --垃圾回收关键字collectgarbag --获取当前lua占用内存数 k字节 返回值*1024就可以得到具体占用字节数 print(collectgarbage("count&…

运营商三要素验证API接口怎么对接

运营商三要素验证API接口又叫手机三要素验证API接口、运营商实名认证接口&#xff0c;这个接口是验证姓名、身份证号、手机号三者是否一致&#xff0c;返回验证结果&#xff0c;如果一致则说明三者信息匹配&#xff0c;可以有效确认当前注册用户的身份信息&#xff0c;那么运营…

系统集成项目管理工程师教程,第2章领读文字简化版来啦

上周六晚上在软考中项内进行了第2波领读&#xff0c;用18分钟时间领读了中项第3版教程的第2章&#xff0c;考虑到语音没法回放&#xff0c;迟到同学无法回听&#xff0c;所以围绕领读内容的要点&#xff0c;今天简要整理了一篇文字稿。 不过文字稿是精简版&#xff0c;如果你需…

在Vue3中如何使用H.265视频流媒体播放器EasyPlayer.js?

H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;可支持H.264与H.265编码格式&#xff0c;性能稳定、播放流畅&#xff0c;能支持WebSocket-FLV、HTTP-FLV&#xff0c;HLS&#xff08;m3u8&#…