多进程
OVERVIEW
- 多进程
- 一、进程创建
- 1.创建1个子进程
- 2.创建多个子进程
- 二、进程控制
- 1.进程结束
- 2.进程等待
- 3.子进程操作1
- 4.子进程操作2
- 三、进程体系
- 1.守护进程
- 2.进程调度
- 程序:一种已经编译好的、存在磁盘中的二进制文件(脚本为普通文件)。
- 进程:运行程序后,程序被调入内存中的状态(程序在内存中的镜像),如果程序够大则可称为应用。
- 线程:线程是进程内的活动单元,每个线程包含自己的虚拟存储器,包括:栈、进程状态/寄存器、指令指针(在单线程的进程中,进程即线程)。
进程ID—PID:
- 默认为int16位,其最大值为32768
- 系统中的第一个进程为system或者init,进程ID为1,故称为1号进程。
- 0号进程是存在的,当没有其他进程运行时,内核运行的进程id为0,称为空闲进程。
- PID的分配:进程ID从1开始递增分配,到最大值后重新开始由最小的未使用的ID开始分配。
一、进程创建
1.创建1个子进程
#include "head.h"
int main() {
pid_t pid;
if ((pid = fork()) < 0) {//创建进程
perror("fork()");
exit(1);
}
//fork在没有出错的情况下有两种返回情况 在父进程中返回子进程的PID 在子进程中返回0
if (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;
}
关于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;
}
二、进程控制
1.进程结束
2.进程等待
#include "head.h"
int main() {
pid_t pid;
if ((pid = fork()) < 0) {//创建进程
perror("fork()");
exit(1);
}
//fork在没有出错的情况下有两种返回情况 在父进程中返回子进程的PID 在子进程中返回0
if (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;
}
注: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;
}
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;
}
#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;
}
注:调用execl系统调用时,原有的进程空间会被替换出去,替换成需要运行程序的进程空间(代码段部分、数据部分)。
4.子进程操作2
- 打开一个c文件,
- 如果文件不存在则新建(用vim打开并编辑),编辑结束保存退出vim,同时编译该文件并执行
- 如果该文件已经存在,直接编译文件并执行。
#include "head.h"
int main(int argc, char *argv[]) {
if (argc == 1) {
fprintf(stderr, "Usage : ./%s filename!\n", argv[0]);
exit(1);
}
//1.打开当前文件夹opendir 读文件夹下的文件readdir
int 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
自动编译并运行target.c得到结果,
三、进程体系
1.守护进程
2.进程调度
进程调度器,是一个内核子系统,把有限的处理器资源分配给系统中的各个进程(决定哪个进程来运行)。
- 阻塞:正在睡眠等待IO,等待信息继续执行下一步。
- 就绪:进程获得所需的资源,可以进行下一步执行。
- 运行: