【Linux系统编程】05:多进程
迪丽瓦拉
2024-06-01 06:31:19
0

多进程


OVERVIEW

  • 多进程
      • 一、进程创建
        • 1.创建1个子进程
        • 2.创建多个子进程
      • 二、进程控制
        • 1.进程结束
        • 2.进程等待
        • 3.子进程操作1
        • 4.子进程操作2
      • 三、进程体系
        • 1.守护进程
        • 2.进程调度

  • 程序:一种已经编译好的、存在磁盘中的二进制文件(脚本为普通文件)。
  • 进程:运行程序后,程序被调入内存中的状态(程序在内存中的镜像),如果程序够大则可称为应用。
  • 线程:线程是进程内的活动单元,每个线程包含自己的虚拟存储器,包括:栈、进程状态/寄存器、指令指针(在单线程的进程中,进程即线程)。

image-20230217193449578

进程ID—PID

  • 默认为int16位,其最大值为32768
  • 系统中的第一个进程为system或者init,进程ID为1,故称为1号进程。
  • 0号进程是存在的,当没有其他进程运行时,内核运行的进程id为0,称为空闲进程。
  • PID的分配:进程ID从1开始递增分配,到最大值后重新开始由最小的未使用的ID开始分配。

一、进程创建

1.创建1个子进程

image-20230217194836636

#include "head.h"int main() {pid_t pid;if ((pid = fork()) < 0) {//创建进程perror("fork()");exit(1);}//fork在没有出错的情况下有两种返回情况 在父进程中返回子进程的PID 在子进程中返回0if (pid == 0 ) {printf("I am child , pid = %d, ppid = %d \n", getpid(), getppid());//子进程} else {printf("I am father my child is %d , pid = %d, ppid = %d, \n", pid, getpid(), getppid());//父进程}return 0;
}

image-20230220105308408

关于fork写拷贝机制节省资源:创建子进程时,将空间分成很多个页,如果在某页中有写操作则将该页复制进行修改。

2.创建多个子进程

#include "head.h"int main() {int i;pid_t pid;for (i = 1; i <= 10; ++i) {if ((pid = fork()) < 0) {perror("fork()");exit(1);}if (pid == 0) break;//如果是子进程退出for循环, 如果是父进程for循环继续}if (pid == 0) printf("i am the %dth child, pid = %d, ppid = %d \n", i, getpid(), getppid());//输出子进程信息else printf("i am the father, pid = %d, ppid = %d \n", getpid(), getppid());//输出父进程信息return 0;
}

image-20230220113923284

二、进程控制

1.进程结束

image-20230220114735155

2.进程等待

image-20230220115123039

#include "head.h"int main() {pid_t pid;if ((pid = fork()) < 0) {//创建进程perror("fork()");exit(1);}//fork在没有出错的情况下有两种返回情况 在父进程中返回子进程的PID 在子进程中返回0if (pid == 0 ) {printf("I am child , pid = %d, ppid = %d \n", getpid(), getppid());//子进程} else {wait(NULL);printf("I am father my child is %d , pid = %d, ppid = %d, \n", pid, getpid(), getppid());//父进程}return 0;
}

image-20230220120059292

注:wait能够帮助父进程监控子进程的结束状态,只有子进程结束之后,父进程才会结束。

#include "head.h"int main() {int i;pid_t pid;for (i = 1; i <= 10; ++i) {sleep(1);if ((pid = fork()) < 0) {perror("fork()");exit(1);}if (pid == 0) break;//如果是子进程退出for循环, 如果是父进程for循环继续}if (pid == 0) printf("i am the %dth child, pid = %d, ppid = %d \n", i, getpid(), getppid());//输出子进程信息else {for (int k = 1; k <= 10; ++k) wait(NULL);printf("i am the father, pid = %d, ppid = %d \n", getpid(), getppid());//输出父进程信息}return 0;
}

image-20230220121002987

3.子进程操作1

#include "head.h"int main() {pid_t pid;if ((pid = fork()) < 0) {perror("fork()");exit(1);}if (pid == 0) {execl("/bin/cat", "cat", "2.exec.c", NULL);} else {wait(NULL);printf("i am the father!\n");}return 0;
}

image-20230223112943046

#include "head.h"int main() {pid_t pid;if ((pid = fork()) < 0) {perror("fork()");exit(1);}if (pid == 0) {execl("/usr/bin/gcc", "gcc", "1.fork.c", "-I", "../common/", NULL);} else {wait(NULL);printf("i am the father!\n");}return 0;
}

image-20230223113256328

注:调用execl系统调用时,原有的进程空间会被替换出去,替换成需要运行程序的进程空间(代码段部分、数据部分)。

4.子进程操作2

  1. 打开一个c文件,
  2. 如果文件不存在则新建(用vim打开并编辑),编辑结束保存退出vim,同时编译该文件并执行
  3. 如果该文件已经存在,直接编译文件并执行。
#include "head.h"int main(int argc, char *argv[]) {if (argc == 1) {fprintf(stderr, "Usage : ./%s filename!\n", argv[0]);exit(1);}//1.打开当前文件夹opendir 读文件夹下的文件readdirint flag = 0;DIR *dirptr;dirptr = opendir(".");struct dirent *dir;while ((dir = readdir(dirptr)) != NULL) {if (!strcmp(dir->d_name, argv[1])) flag = 1;//文件存在则flag置位1}//2.如果文件不存在则新建文件 并使用vim打开进行编辑pid_t pid;if (flag == 0) {int fd;if ((fd = open(argv[1], O_RDWR | O_CREAT, 0644)) < 0) {perror("open");exit(1);}if ((pid = fork()) < 0) {perror("fork1");exit(1);}if (pid == 0) {//子进程vim打开文件并进行编辑execl("/usr/bin/vim", "vim", argv[1], NULL);}}wait(NULL);//3.编译并执行文件if ((pid = fork()) < 0) {perror("fork2-1");exit(1);}if (pid == 0) {execl("/usr/bin/gcc", "gcc", argv[1], "-o", "target.out", NULL);//编译文件} else {wait(NULL);if ((pid = fork()) < 0) {perror("fork2-2");exit(1);}if (pid == 0) {execl("./target.out", "target.out", NULL);//执行文件} else {wait(NULL);}}return 0;
}

打开文件夹中不存在的文件,自动使用vim打开,写入test1.c

image-20230223192429681

自动编译并运行target.c得到结果,

image-20230223192542219

三、进程体系

1.守护进程

image-20230223194209605

2.进程调度

进程调度器,是一个内核子系统,把有限的处理器资源分配给系统中的各个进程(决定哪个进程来运行)。

  • 阻塞:正在睡眠等待IO,等待信息继续执行下一步。
  • 就绪:进程获得所需的资源,可以进行下一步执行。
  • 运行:

image-20230223212603665

相关内容