Linux 程式基礎

所眼皆星河發表於2020-12-30

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

相關文章