signed

QiShunwang

“诚信为本、客户至上”

Linux 进程基础

2020/12/30 4:02:54   来源:

Linux 进程基础

    • PCB
    • 进程控制
      • fork函数
        • 创建一个子进程
        • 循环创建n个子进程
      • 进程共享
    • 参考

PCB

PCB(进程描述符)位于内核空间中,每个进程的PCB是不同的,PCB是一个task_struct[1]结构体包括:

  • 进程id。每个进程都有一个唯一id,类型为pid_t(非负整数)。

  • 进程状态。就绪、运行、阻塞、停止。

  • 进程切换时需要保存和恢复的CPU寄存器。

  • VM与PM的映射,由MMU转化,保存在PCB中。

  • 当前工作目录。

  • umask掩码,提供文件权限相关。

  • 文件描述符表。

  • 信号相关信息。

  • 用户id和组id。

在这里插入图片描述

进程控制

fork函数

FORK(2)                        Linux Programmer's Manual                        FORK(2)

NAME
       fork - create a child process

SYNOPSIS
       #include <unistd.h>

       pid_t fork(void);

DESCRIPTION
       fork()  creates  a  new  process  by  duplicating  the calling process.  The new
       process is referred to as the child process.  The calling process is referred to
       as the parent process.
RETURN VALUE
       On success, the PID of the child process is returned in the  parent,  and  0  is
       returned  in  the  child.   On  failure,  -1 is returned in the parent, no child
       process is created, and errno is set appropriately.

返回值有两个,大于0代表父进程,等于0代表子进程(子进程成功被创建)。

创建一个子进程

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
	pid_t pid;
	
	printf("======before======\n");
	
	pid = fork();
	
	if (pid == -1) {
		printf("fork error");
		exit(1);
	} else if (pid == 0) {
		printf("===child, pid = %u, ppid = %u\n", getpid(), getppid());
	} else {
		printf("===parent, pid = %u, ppid = %u\n", getpid(), getppid());
		sleep(1);
	}
	
	printf("======after======\n");
	return 0;
}
~# ./test
======before======
===parent, pid = 9215, ppid = 8980
===child, pid = 9216, ppid = 9215
======after======
======after======

循环创建n个子进程

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
	pid_t pid;
	int n = 5;
	printf("======before======\n");
	
	int i;
	for (i = 0; i < n; i++) {
		pid = fork();
		if (pid == -1) {
			printf("fork error");
			exit(1);
		} else if (pid == 0) {
			//printf("===child, pid = %u, ppid = %u\n", getpid(), getppid());
			//如果是子进程的话,直接跳出循环~
			break;
		} else {
			//只有父进程继续执行 创建子进程
		}
	}
	
	if (i < n) {
		printf("child %dth, pid = %u, ppid = %u\n", i + 1, getpid(), getppid());
	}

	return 0;
}
~# ./test
child 5th, pid = 9345, ppid = 1
child 4th, pid = 9344, ppid = 1
child 3th, pid = 9343, ppid = 1
child 2th, pid = 9342, ppid = 1
child 1th, pid = 9341, ppid = 1

进程共享

fork之后

共享:全局变量、.data、.text、栈、堆、…

不共享:进程ID,fork返回值,父进程ID,进程运行时间,定时器,未决信号集。

fork之后

共享:文件描述符和mmap建立的映射区。

注意:全局变量也不会共享的。

父子进程遵循读时共享写时复制原则。

参考

[1] https://elixir.bootlin.com/linux/v4.1.15/source/include/linux/sched.h#L1292