Linux系统【一】CPU+MMU+fork函数创建进程

切板中的内容输出到文件### 进程相关概念
程序:编译好的二进制文件,在磁盘上,不占用系统资源(不包括磁盘)。(剧本)
进程:占用系统资源,是程序的一次运行。(戏剧)

一个程序可以产生多个进程,一个进程可以调用多个程序

并发:并行执行

单道程序设计:DOS系统
多道程序设计:时钟中断

中央处理器CPU

存储介质:按照容量从大到小:

硬盘->内存->cache(高速缓存)->寄存器

预取器:从cache中取出指令
译码器:解析指令
算数逻辑单元(ALU):只会+<<
寄存器堆:ALU操作的寄存器扎堆的地方
然后再将寄存器中的值返回给cache

MMU

MMU位于CPU内部:负责虚拟内存和物理内存之间的映射,设置修改内存访问的级别(CPU中设置了0-3四个等级,Linux系统中用到0级内核区和3级用户区)
每产生一个进程产生一个虚拟内存:可用的地址空间
每次最小分配物理内存4K(一个page)
同一个程序的不同进程的kernel区内存映射到同一个空间,但是使用的是不同的PCB

PCB

处于kernel区,进程描述符\进程控制块,实际上是一个task_struct结构体,里面有很多的成员

  • 进程的id,无符号整数
  • 进程状态:初状态、就绪状态、运行状态、挂起状态、终止状态
  • 进程切换时候需要保存和恢复的一些寄存器
  • 描述虚拟地址空间的信息
  • 描述控制终端的信息
  • 当前进程的工作目录
  • umask掩码
  • 文件描述符表
  • 和信号相关的信息
  • 用户id和组id
  • 会话和进程组
  • 进程可以使用的资源上限ulimit -a

环境变量

Linux系统是多用户多任务的开源操作系统
用户操作计算机的时候运行的一些信息通过环境变量进行设置

  • 字符串char * environ[],存储在用户区,高于stack的起始位置
  • 统一的存储格式:名字=值[:值]
  • 值用来描述进程环境信息

shell为例,所使用的环境变量为PATH,在解析命令的时候按照PATH中的内容从前往后逐个目录进行查找,因此如果希望使用新版本软件应该把新版本软件的环境变量向前移动

SHELL 所使用的命令解析器在哪里
HOME 家目录在哪里
LANG	使用的是什么语言
TERM	所使用的终端类型,图形界面所使用的一般是xterm,可以显示汉字,字符界面一般不可以

通过程序打印所有的环境变量:

#include<stdio.h>extern char ** environ;//引入环境变量表int main(void)
{int i;for(int i=0;environ[i]!=NULL;++i){printf("%s\n",environ[i]);}return 0;
}

相关函数

  • getenv
    手册第三章
  • setenv
  • unsetenv删除环境变量:即使没有那个环境变量也会返回成功,只有当参数为已经有的环境变量的非法格式例如:name=才会报错,例如:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>int main()
{const char* name="123ABC";char *val;setenv(name,"123",1);printf("%d\n",unsetenv("123ABC=1"));	//-1printf("%d\n",unsetenv("123ABC"));			//0return 0;
}

进程控制

创建进程的方法:

  • 运行可执行程序
  • 通过fork函数创建子进程

fork函数创建子进程

#include<unistd.h>
pid_t fork(void)	

fork两个成功返回值
如果子进程创建失败则返回-1,并且将错误信息保存在erron中,我们可以使用perror输出错误信息。
如果子进程创建成功则会在父进程中返回子进程的ID,在子进程中返回0

父进程的fork返回子进程ID,子进程的fork返回值为0,通过对返回值的判断处于哪个进程
可执行文件的父进程是bash

创建单个进程
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>int main()
{printf("begin:\n");pid_t pid = fork();if(-1 == pid){perror("process creat:");exit(1);}else if(0 == pid){printf("This is son process,pid = %d \n",(int)getpid());printf("My father process pid = %d \n",(int)getppid());}else{printf("This is father process,pid = %d \n",(int)getpid());printf("My father process pid = %d \n",(int)getppid());sleep(1);}printf("end\n");return 0;
}

循环创建N个子进程

如果直接使用循环进行创建,则n层循环会创建2n-1个子进程,这显然不是我们需要的。
因此我们需要在子进程中直接跳出循环,这样就不会产生过多的子进程

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>int main(int argc,char* argv[])
{if(argc<2){printf("too few arguments\n");exit(1);}if(argc>2){printf("too few arguments\n");exit(1);}int i,limit=argv[1][0]-'0';printf("begin:\n");for(i=0;i<limit;++i){pid_t pid = fork();if(-1 == pid){perror("process creat:");exit(1);}else if(0 == pid){printf("This is %dth son process,pid = %d \n",i+1,(int)getpid());printf("My father process pid = %d \n",(int)getppid());break;}
}printf("end\n");return 0;
}

在《APUE》中说到如果不加控制的话父进程有98%的可能性获得CPU的控制权(不过我的电脑上并不是这样),由内核的调度算法决

getuid

获取当前进程实际用户IDuid_t getuid(void);
获取当前进程有效用户IDuid_t geteuid(void);

getgid

获取当前进程实际用户组IDgid_t getgid(void);
获取当前进程有效用户组IDgid_t getegid(void);

进程共享

父子进程相同的:全局变量、.data,.text,栈、共享库、堆、环境变量、用户ID、宿主目录、进程工作目录、信号处理方式都是相同的
父子进程对于前面的变量的处理:读时共享写时复制
如果子进程只对前面的数据进行读取,则和父进程共享同一个变量,如果对前面的数据进行修改(写,改变),则复制一份新的,指针的话会制定一个新的地址。
父子进程不同的:进程ID,fork返回值,父进程ID,进程运行时间,闹钟(定时器),未决信号集
进程运行时间:子进程的运行时间为父进程fork()调用时间
父子进程共享:

  • 文件描述符
  • mmap建立的映射区(进程间的通信)
    我自己写了一个测试程序
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>int main(int argc,char* argv[])
{int fd=open("test",O_CREAT | O_RDWR | O_TRUNC,0644);pid_t fid=getppid();if(argc<2){printf("too few arguments\n");exit(1);}if(argc>2){printf("too few arguments\n");exit(1);}int i,limit=argv[1][0]-'0';printf("begin:\n");for(i=0;i<limit;++i){pid_t pid = fork();if(-1 == pid){perror("process creat:");exit(1);}else if(0 == pid){break;}}char buffer[100];memset(buffer,0,sizeof(buffer));int sz=sprintf(buffer,"This is %dth son process,pid = %d \n",i+1,(int)getpid());write(fd,buffer,sz);if(getppid()==fid){close(fd);printf("end\n");}return 0;
}

gdb调试

使用gdb调试的时候,gdb只能跟踪一个进程,可以在fork函数调用之前,通过执行设置gdb调试工具跟踪父进程或者是跟踪子进程,默认跟踪父进程。

  • set follow-fork-mode child命令设置gdb在fork之后跟踪子进程
  • set follow-fork-mod parent设置跟踪父进程
  • 注意一定在fork函数调用前设置才有效

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

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

相关文章

Ubuntu卸载软件

用过使用dpkg软件管理工具得到所有已经安装的软件&#xff0c;如果不清楚软件的全名可以使用grep命令进行查找 然后再使用sudo apt-get remove --purge 软件名卸载软件&#xff08;--purge参数会删除配置文件&#xff0c;删的干净一些&#xff09; 例如&#xff1a;

一个重要且实用的signal---SIGCHLD

https://blog.csdn.net/lyztyycode/article/details/78150805SIGCHLD(修改)因为笔者之前的文章里面有错误&#xff0c;今天发现&#xff0c;立马做个修改。在下面我的一段关于sigchld信号相对于直接调用wait函数的好处时&#xff0c;我说调用wait函数要一直检测子进程是否执行完…

数据结构实验之链表七:单链表中重复元素的删除

https://blog.csdn.net/blessingxry/article/details/794455111.知识点&#xff1a;逆序建立链表&#xff0b;节点删除 2.题意&#xff1a;按照数据输入的相反顺序&#xff08;逆位序&#xff09;建立一个单链表&#xff0c;并将单链表中重复的元素删除&#xff08;值相同的元素…

Python3函数和代码复用

函数的定义 def 函数名([参数列表]):注释函数体注意事项 函数形参不需要声明类型&#xff0c;可以使用return语句在结束函数执行的同时返回任意类型的值&#xff0c;函数返回值类型与return语句返回表达式i的类型一致 即使该函数不需要接受任何参数&#xff0c;也必须保留一堆…

一文说尽C++赋值运算符重载函数(operator=)

http://www.cnblogs.com/zpcdbky/p/5027481.html在前面&#xff1a;关于C的赋值运算符重载函数(operator)&#xff0c;网络以及各种教材上都有很多介绍&#xff0c;但可惜的是&#xff0c;内容大多雷同且不全面。面对这一局面&#xff0c;在下在整合各种资源及融入个人理解的基…

Python a和a[:]的区别

简单来讲a[:]是深复制&#xff0c;a是浅复制&#xff0c;相当于赋值a的话是赋值了指针&#xff0c;赋值a[:]相当于复制了a对应的那段空间 例如&#xff1a; a [1,1,1,1,1,1]for x in a:if x1:a.remove(x)print(a)运行结果&#xff1a; remove操作是移除序列中第一个x元素。…

约瑟夫环(c语言程序完整版)

https://blog.csdn.net/m_hahahaha1994/article/details/51742453约瑟夫环&#xff08;约瑟夫问题&#xff09;是一个数学的应用问题&#xff1a;已知n个人&#xff08;以编号1&#xff0c;2&#xff0c;3…n分别表示&#xff09;围坐在一张圆桌周围。从编号为k的人开始报数&am…

Linux系统【二】exec族函数及应用

文件描述符 文件描述符表是一个指针数组&#xff0c;文件描述符是一个整数。 文件描述符表对应的指针是一个结构体&#xff0c;名字为file_struct&#xff0c;里面保存的是已经打开文件的信息 需要注意的是父子进程之间读时共享&#xff0c;写时复制的原则是针对物理地址而言…

白话C++系列(27) -- RTTI:运行时类型识别

http://www.cnblogs.com/kkdd-2013/p/5601783.htmlRTTI—运行时类型识别 RTTI&#xff1a;Run-Time Type Identification。 那么RTTI如何来体现呢&#xff1f;这就要涉及到typeid和dynamic_cast这两个知识点了。为了更好的去理解&#xff0c;那么我们就通过一个例子来说明。这个…

使用头文件的原因和规范

原因 通过头文件来调用库功能。在很多场合&#xff0c;源代码不便&#xff08;或不准&#xff09;向用户公布&#xff0c;只 要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库 功能&#xff0c;而不必关心接口怎么实现的。编译器会从库中提取相应…

转圈踢人问题

https://www.cnblogs.com/lanxuezaipiao/p/3339603.html 有N个人围一圈依次报数&#xff0c;数到3的倍数的人出列&#xff0c;问当只剩一个人时他原来的位子在哪里&#xff1f; 解答&#xff1a;经典的转圈踢人问题&#xff0c;好吧专业一点&#xff0c;约瑟夫环问题&#xff0…

Linux系统【三】回收子进程

孤儿进程 父进程先于子进程结束&#xff0c;则子进程成为孤儿进程&#xff0c;子进程的父进程成为init进程&#xff0c;则称init进程领养孤儿进程。现在好像是用户进程中的system进程。 僵尸进程 进程终止&#xff0c;父进程不进行回收&#xff0c;自己成残留资源(PCB)存放在…

string类的基本实现

https://blog.csdn.net/qq_29503203/article/details/52265829在面试中面试官常常会让你写出string类的基本操作&#xff0c;比如&#xff1a;构造函数&#xff0c;析构函数&#xff0c;拷贝构造等等.下面是除此之外的一些操作&#xff0c;希望可以帮助你更好的理解string以便以…

Python3常用数据结构

Python3中有三种组合数据类型&#xff0c;分别为&#xff1a; 序列类型&#xff1a;字符串&#xff08;str&#xff09;、元组&#xff08;tuple&#xff09;、列表&#xff08;list&#xff09;集合类型&#xff1a;集合&#xff08;set&#xff09;映射类型&#xff1a;字典…

Linux C++ 回射服务器

http://blog.csdn.net/qq_25425023/article/details/53914820回射服务器就是服务端将客户端的数据发送回去。我实现的回射服务器返回增加了时间。服务端代码&#xff0c;可以很容易看懂&#xff1a;[cpp] view plaincopy#include <sys/socket.h> #include <stdio.h&g…

TCP第四次挥手为什么要等待2MSL

当客户端进入TIME-WAIT状态的时候(也就是第四次挥手的时候)&#xff0c;必须经过时间计数器设置的时间2MSL(最长报文段寿命)后&#xff0c;才能进入关闭状态&#xff0c;这时为什么呢&#xff1f;&#xff1f;&#xff1f; 这最主要是因为两个理由&#xff1a; 1、为了保证客户…

计算机网络【一】概述+OSI参考模型

网络概述 局域网:覆盖范围小(100m以内)&#xff0c;自己花钱买设备&#xff0c;带宽固定(10M,100M,1000M)&#xff0c;自己维护&#xff08;接入层交换机直接连接电脑、汇聚层交换机直接连接接入层交换机&#xff09; 广域网:距离远&#xff0c;花钱买服务&#xff0c;租带宽&…

单链表逆序的多种方式

https://www.cnblogs.com/eniac12/p/4860642.htmltemplate<class T> void List<T>::Inverse() {if(first NULL) return;LinkNode<T> *p, *prev, *latter; p first->link;   // 当前结点prev NULL;   // 前一结点l…

Linux系统【四】进程间通信-管道

进程间通信&#xff08;IPC Interprocess Communication&#xff09; 进程和进程之间的通信只能通过内核&#xff0c;在内核中提供一块缓冲区进行通信。内核提供的这种机制叫做IPC 在进程间完成数据传输需要借助操作系统提供的特殊方法&#xff0c;如&#xff1a;文件&#xf…

单链表各种操作详解

#include "stdio.h" #include "stdlib.h"#define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0#define MAXSIZE 20 /* 存储空间初始分配量 */typedef int Status;/* Status是函数的类型,其值是函数结果状态代码&#xff0c;如OK等 */ typedef int…