中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

做視頻網(wǎng)站如何賺錢品牌推廣的渠道有哪些

做視頻網(wǎng)站如何賺錢,品牌推廣的渠道有哪些,南京做網(wǎng)站團(tuán)隊(duì),學(xué)做網(wǎng)站視頻論壇1. 進(jìn)程的基礎(chǔ)概念 1.1 進(jìn)程是什么? 定義: 進(jìn)程是操作系統(tǒng)管理的一個(gè)程序?qū)嵗?。它包含程序代碼及其當(dāng)前活動(dòng)的狀態(tài)。每個(gè)進(jìn)程有自己的內(nèi)存地址空間,擁有獨(dú)立的棧、堆、全局變量等。操作系統(tǒng)通過(guò)進(jìn)程來(lái)分配資源(如 CPU 時(shí)間、內(nèi)…

1. 進(jìn)程的基礎(chǔ)概念

1.1 進(jìn)程是什么?

定義

  • 進(jìn)程是操作系統(tǒng)管理的一個(gè)程序?qū)嵗?。它包含程序代碼及其當(dāng)前活動(dòng)的狀態(tài)。每個(gè)進(jìn)程有自己的內(nèi)存地址空間,擁有獨(dú)立的棧、堆、全局變量等。操作系統(tǒng)通過(guò)進(jìn)程來(lái)分配資源(如 CPU 時(shí)間、內(nèi)存等)并管理任務(wù)的執(zhí)行。

進(jìn)程 vs 程序

  • 程序:靜態(tài)的代碼和數(shù)據(jù),存儲(chǔ)在磁盤上。
  • 進(jìn)程:程序的一個(gè)運(yùn)行實(shí)例,包括程序的代碼、活動(dòng)狀態(tài)、資源等。

1.2 進(jìn)程的內(nèi)存布局

一個(gè)典型進(jìn)程的內(nèi)存分布如下:

內(nèi)存段描述
(Stack)存儲(chǔ)函數(shù)調(diào)用時(shí)的局部變量、函數(shù)調(diào)用鏈等。棧從高地址向低地址增長(zhǎng)。
空間(Gap)堆和棧之間未分配的內(nèi)存區(qū)域,用于防止二者相互干擾。
(Heap)用于動(dòng)態(tài)內(nèi)存分配(如使用 malloc()),堆從低地址向高地址增長(zhǎng)。
BSS段(BSS Segment)存儲(chǔ)未初始化的全局變量和靜態(tài)變量。
數(shù)據(jù)段(Data Segment)存儲(chǔ)已初始化的全局變量和靜態(tài)變量。
代碼段(Text Segment)存儲(chǔ)程序的代碼,即指令。
#include <stdio.h>
#include <stdlib.h>// 全局變量(已初始化) - 數(shù)據(jù)段
int global_initialized = 42;// 靜態(tài)變量(未初始化) - BSS 段
static int static_uninitialized;// 函數(shù) - 代碼段
void display_addresses() {// 局部變量 - 棧段int local_variable = 0;printf("代碼段 (Text Segment): %p\n", (void*)display_addresses);printf("數(shù)據(jù)段 (Data Segment) (已初始化全局變量): %p\n", (void*)&global_initialized);printf("BSS 段 (BSS Segment) (未初始化靜態(tài)變量): %p\n", (void*)&static_uninitialized);printf("棧段 (Stack Segment) (局部變量): %p\n", (void*)&local_variable);
}int main() {// 堆內(nèi)存 - 堆段int* heap_variable = (int*)malloc(10 * sizeof(int));// 顯示各內(nèi)存段的地址display_addresses();printf("堆段 (Heap Segment) (動(dòng)態(tài)分配內(nèi)存): %p\n", (void*)heap_variable);// 再次分配內(nèi)存,看看堆地址是否變化int* heap_variable2 = (int*)malloc(10 * sizeof(int));printf("堆段 (Heap Segment) (再次分配內(nèi)存): %p\n", (void*)heap_variable2);// 釋放內(nèi)free(heap_variable);free(heap_variable2);return 0;
}

運(yùn)行結(jié)果:

代碼段 (Text Segment): 0x55d05bad21a9
數(shù)據(jù)段 (Data Segment) (已初始化全局變量): 0x55d05bad5010
BSS 段 (BSS Segment) (未初始化靜態(tài)變量): 0x55d05bad5018
棧段 (Stack Segment) (局部變量): 0x7ffc49a5c084
堆段 (Heap Segment) (動(dòng)態(tài)分配內(nèi)存): 0x55d05c49c2a0
堆段 (Heap Segment) (再次分配內(nèi)存): 0x55d05c49c6e0

1.3 進(jìn)程的生命周期

進(jìn)程在操作系統(tǒng)中的生命周期包括以下幾個(gè)狀態(tài):

進(jìn)程狀態(tài)描述
新建(New)進(jìn)程被創(chuàng)建,操作系統(tǒng)為其分配資源。
就緒(Ready)進(jìn)程已經(jīng)準(zhǔn)備好運(yùn)行,等待調(diào)度器分配 CPU。
運(yùn)行(Running)進(jìn)程正在 CPU 上執(zhí)行指令。
阻塞(Blocked/Waiting)進(jìn)程在等待某些條件(如 I/O 操作完成),無(wú)法繼續(xù)執(zhí)行。
終止(Terminated)進(jìn)程執(zhí)行完畢或被強(qiáng)制終止,操作系統(tǒng)回收其資源。

狀態(tài)轉(zhuǎn)換圖

在這里插入圖片描述

新建 (New)就緒 (Ready):
當(dāng)一個(gè)新進(jìn)程被創(chuàng)建且已經(jīng)準(zhǔn)備好運(yùn)行時(shí),它從“新建”狀態(tài)轉(zhuǎn)變?yōu)椤熬途w”狀態(tài)。

就緒 (Ready)運(yùn)行 (Running):
當(dāng)調(diào)度程序選擇一個(gè)就緒狀態(tài)的進(jìn)程來(lái)運(yùn)行時(shí),它從“就緒”狀態(tài)轉(zhuǎn)變?yōu)椤斑\(yùn)行”狀態(tài)。

運(yùn)行 (Running)阻塞 (Blocked):
如果運(yùn)行中的進(jìn)程需要等待某些資源(如I/O操作),它會(huì)從“運(yùn)行”狀態(tài)轉(zhuǎn)變?yōu)椤白枞睜顟B(tài)。

阻塞 (Blocked)就緒 (Ready):
當(dāng)阻塞狀態(tài)的進(jìn)程等待的事件發(fā)生后,它會(huì)重新進(jìn)入“就緒”狀態(tài),準(zhǔn)備再次運(yùn)行。

運(yùn)行 (Running)就緒 (Ready):
如果進(jìn)程由于某種原因沒(méi)有完成執(zhí)行而被中斷,它將從“運(yùn)行”狀態(tài)返回到“就緒”狀態(tài),等待下次被調(diào)度。

運(yùn)行 (Running)終止 (Term):
當(dāng)進(jìn)程完成執(zhí)行或被強(qiáng)制終止時(shí),它從“運(yùn)行”狀態(tài)轉(zhuǎn)變?yōu)椤敖K止”狀態(tài)。

2. 進(jìn)程的創(chuàng)建與管理

進(jìn)程的創(chuàng)建與管理是操作系統(tǒng)并發(fā)機(jī)制的核心。在 Unix/Linux 系統(tǒng)中,fork()exec() 是創(chuàng)建和管理進(jìn)程的兩個(gè)主要系統(tǒng)調(diào)用。

2.1 使用 fork() 創(chuàng)建進(jìn)程

fork() 是 Unix/Linux 中用于創(chuàng)建新進(jìn)程的系統(tǒng)調(diào)用。它會(huì)復(fù)制當(dāng)前進(jìn)程,創(chuàng)建一個(gè)新的子進(jìn)程。子進(jìn)程幾乎完全與父進(jìn)程相同,但它們有獨(dú)立的內(nèi)存空間和資源。

#include <stdio.h>
#include <unistd.h>int main() {pid_t pid = fork();  // 創(chuàng)建一個(gè)子進(jìn)程if (pid < 0) {// fork() 失敗perror("Fork failed");return 1;} else if (pid == 0) {// 子進(jìn)程代碼printf("This is the child process with PID: %d\n", getpid());} else {// 父進(jìn)程代碼printf("This is the parent process with PID: %d\n", getpid());printf("Created child process with PID: %d\n", pid);}return 0;
}

運(yùn)行結(jié)果:

This is the parent process with PID: 1683911
Created child process with PID: 1683912
liber@liber-VMware-Virtual-Platform:/home/c$ This is the child process with PID: 1683912

解釋

  • fork() 創(chuàng)建一個(gè)新的子進(jìn)程,子進(jìn)程是父進(jìn)程的副本。
  • pid_t pid = fork()fork() 返回兩次,一次在父進(jìn)程中返回子進(jìn)程的 PID,一次在子進(jìn)程中返回 0。通過(guò)判斷 pid 的值,可以區(qū)分當(dāng)前代碼是運(yùn)行在父進(jìn)程還是子進(jìn)程中。

2.2 使用 exec() 系列函數(shù)替換進(jìn)程映像

在創(chuàng)建了子進(jìn)程后,常常需要在子進(jìn)程中執(zhí)行不同的程序,這時(shí)可以使用 exec() 系列函數(shù)來(lái)替換當(dāng)前進(jìn)程的映像。exec() 系列函數(shù)包括 execl()execv()、execlp()、execvp() 等。

下面是關(guān)于 exec 系列函數(shù)概述的表格,展示了每個(gè)函數(shù)的使用方式、參數(shù)類型及其特點(diǎn):

函數(shù)名稱參數(shù)類型程序路徑查找方式說(shuō)明
execl()參數(shù)列表(可變參數(shù))需要指定完整路徑不查找路徑通過(guò)傳遞一個(gè)參數(shù)列表執(zhí)行指定路徑的程序,參數(shù)列表必須以NULL結(jié)尾。
execv()參數(shù)數(shù)組需要指定完整路徑不查找路徑通過(guò)傳遞一個(gè)參數(shù)數(shù)組執(zhí)行指定路徑的程序,參數(shù)數(shù)組最后一個(gè)元素必須是NULL。
execlp()參數(shù)列表(可變參數(shù))只需指定程序名稱使用PATH查找通過(guò)傳遞一個(gè)參數(shù)列表執(zhí)行指定名稱的程序,系統(tǒng)在PATH環(huán)境變量中查找該程序的路徑。參數(shù)列表必須以NULL結(jié)尾。
execvp()參數(shù)數(shù)組只需指定程序名稱使用PATH查找通過(guò)傳遞一個(gè)參數(shù)數(shù)組執(zhí)行指定名稱的程序,系統(tǒng)在PATH環(huán)境變量中查找該程序的路徑。參數(shù)數(shù)組最后一個(gè)元素必須是NULL。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>int main() {pid_t pid;// 使用 execl() 執(zhí)行 /bin/lspid = fork();if (pid == 0) {// 在子進(jìn)程中執(zhí)行printf("Child process (PID: %d) using execl() to execute /bin/ls -l\n", getpid());execl("/bin/ls", "ls", "-l", NULL);  // 執(zhí)行 ls -lperror("execl failed");exit(EXIT_FAILURE);} else if (pid > 0) {// 父進(jìn)程代碼wait(NULL);  // 等待子進(jìn)程完成printf("execl() Child process completed.\n");}// 使用 execv() 執(zhí)行 /bin/echopid = fork();if (pid == 0) {// 在子進(jìn)程中執(zhí)行printf("Child process (PID: %d) using execv() to execute /bin/echo 'Hello, World!'\n", getpid());char *args1[] = {"/bin/echo", "Hello,", "World!", NULL};execv("/bin/echo", args1);  // 執(zhí)行 echo "Hello, World!"perror("execv failed");exit(EXIT_FAILURE);} else if (pid > 0) {// 父進(jìn)程代碼wait(NULL);  // 等待子進(jìn)程完成printf("execv() Child process completed.\n");}// 使用 execlp() 執(zhí)行 lspid = fork();if (pid == 0) {// 在子進(jìn)程中執(zhí)行printf("Child process (PID: %d) using execlp() to execute ls -a\n", getpid());execlp("ls", "ls", "-a", NULL);  // 執(zhí)行 ls -aperror("execlp failed");exit(EXIT_FAILURE);} else if (pid > 0) {// 父進(jìn)程代碼wait(NULL);  // 等待子進(jìn)程完成printf("execlp() Child process completed.\n");}// 使用 execvp() 執(zhí)行 echopid = fork();if (pid == 0) {// 在子進(jìn)程中執(zhí)行printf("Child process (PID: %d) using execvp() to execute echo 'This is execvp!'\n", getpid());char *args2[] = {"echo", "This", "is", "execvp!", NULL};execvp("echo", args2);  // 執(zhí)行 echo "This is execvp!"perror("execvp failed");exit(EXIT_FAILURE);} else if (pid > 0) {// 父進(jìn)程代碼wait(NULL);  // 等待子進(jìn)程完成printf("execvp() Child process completed.\n");}printf("All child processes completed. Parent process exiting.\n");return 0;
}

運(yùn)行結(jié)果:

Child process (PID: 1697610) using execl() to execute /bin/ls -l
總計(jì) 24
-rwxrwxr-x 1 liber liber 16424 8月 13 22:58 code
-rw-rw-r-- 1 liber liber 2346 8月 13 22:58 code.c
execl() Child process completed.
Child process (PID: 1697612) using execv() to execute /bin/echo ‘Hello, World!’
Hello, World!
execv() Child process completed.
Child process (PID: 1697614) using execlp() to execute ls -a
. … code code.c
execlp() Child process completed.
Child process (PID: 1697616) using execvp() to execute echo ‘This is execvp!’
This is execvp!
execvp() Child process completed.
All child processes completed. Parent process exiting.

解釋

  • 在第一個(gè)子進(jìn)程中,使用execl()函數(shù)執(zhí)行/bin/ls命令。參數(shù)列表包括路徑/bin/ls、程序名稱ls以及命令行參數(shù)-l。如果成功,子進(jìn)程會(huì)替換為ls -l的執(zhí)行。
  • 在第二個(gè)子進(jìn)程中,使用execv()函數(shù)執(zhí)行/bin/echo命令。參數(shù)通過(guò)一個(gè)數(shù)組args1傳遞,包含程序路徑/bin/echo及參數(shù)"Hello," "World!"。如果成功,子進(jìn)程會(huì)輸出Hello, World!。
  • 在第三個(gè)子進(jìn)程中,使用execlp()函數(shù)執(zhí)行ls -a命令。只需要提供程序名稱ls,系統(tǒng)會(huì)在PATH環(huán)境變量中查找ls的路徑。成功時(shí),子進(jìn)程會(huì)替換為ls -a的執(zhí)行。
  • 在第四個(gè)子進(jìn)程中,使用execvp()函數(shù)執(zhí)行echo命令。參數(shù)通過(guò)數(shù)組args2傳遞,包括程序名稱echo及參數(shù)"This", "is", "execvp!"。系統(tǒng)會(huì)在PATH環(huán)境變量中查找echo的路徑。成功時(shí),子進(jìn)程會(huì)輸出This is execvp!。

3. 進(jìn)程的同步與等待

3.1 wait()waitpid() 函數(shù)

父進(jìn)程可以使用 wait()waitpid() 函數(shù)來(lái)等待子進(jìn)程終止,并獲取子進(jìn)程的退出狀態(tài)。waitpid()wait() 的增強(qiáng)版本,允許你等待特定的子進(jìn)程或以非阻塞方式等待。它不僅可以像 wait() 一樣等待任意一個(gè)子進(jìn)程結(jié)束,還可以通過(guò)傳遞子進(jìn)程的 PID 來(lái)等待特定的子進(jìn)程。

wait:

#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>int main() {pid_t pid = fork();  // 創(chuàng)建子進(jìn)程if (pid == 0) {// 子進(jìn)程部分printf("Child process with PID: %d\n", getpid());sleep(2);  // 模擬子進(jìn)程工作} else if (pid > 0) {// 父進(jìn)程部分printf("Parent waiting using wait().\n");wait(NULL);  // 使用 wait() 等待子進(jìn)程printf("Child process has terminated.\n");}return 0;
}

運(yùn)行結(jié)果:

Parent waiting using wait().
Child process with PID: 1777167
Child process has terminated.

解釋

  • 子進(jìn)程執(zhí)行 sleep(2) 來(lái)模擬工作,父進(jìn)程使用 wait() 等待子進(jìn)程結(jié)束。

waitpid:

#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>int main() {pid_t pid = fork();  // 創(chuàng)建子進(jìn)程if (pid == 0) {// 子進(jìn)程部分printf("Child process with PID: %d\n", getpid());sleep(3);  // 模擬子進(jìn)程工作} else if (pid > 0) {// 父進(jìn)程部分printf("Parent waiting using waitpid().\n");waitpid(pid, NULL, 0);  // 使用 waitpid() 等待特定子進(jìn)程printf("Child process has terminated.\n");}return 0;
}

運(yùn)行結(jié)果:

Parent waiting using waitpid().
Child process with PID: 1779327
Child process has terminated.

解釋

  • 子進(jìn)程執(zhí)行 sleep(3) 來(lái)模擬工作,父進(jìn)程使用 waitpid() 等待這個(gè)特定的子進(jìn)程。

4. 進(jìn)程間通信(IPC)

進(jìn)程間通信是多個(gè)進(jìn)程之間交換數(shù)據(jù)的機(jī)制。常見(jiàn)的 IPC 機(jī)制包括管道(Pipes)、消息隊(duì)列(Message Queues)、共享內(nèi)存(Shared Memory)和信號(hào)量(Semaphores)。

4.1 管道(Pipe)

管道是一種常用的 IPC 機(jī)制,允許一個(gè)進(jìn)程向另一個(gè)進(jìn)程傳遞數(shù)據(jù)。管道分為匿名管道和命名管道(FIFO)。

**匿名管道:**適用于有親緣關(guān)系的進(jìn)程間通信,比如父子進(jìn)程。它的特點(diǎn)是臨時(shí)性,不會(huì)在文件系統(tǒng)中留下痕跡。

#include <stdio.h>
#include <unistd.h>int main() {int fd[2];char buffer[30];pipe(fd);  // 創(chuàng)建管道pid_t pid = fork();if (pid == 0) {// 子進(jìn)程:向管道寫入數(shù)據(jù)write(fd[1], "Hello from child", 17);} else if (pid > 0) {// 父進(jìn)程:從管道讀取數(shù)據(jù)read(fd[0], buffer, sizeof(buffer));printf("Received from child process: %s\n", buffer);}return 0;
}

運(yùn)行結(jié)果:

Received from child process: Hello from child

解釋

  • pipe(fd) 創(chuàng)建一個(gè)匿名管道,fd[0] 是讀端,fd[1] 是寫端。
  • 子進(jìn)程寫入數(shù)據(jù),父進(jìn)程從管道讀取數(shù)據(jù),實(shí)現(xiàn)簡(jiǎn)單的進(jìn)程間通信。

**命名管道(FIFO):**是一種特殊的文件,它允許無(wú)親緣關(guān)系的進(jìn)程通過(guò)管道文件進(jìn)行通信。命名管道在文件系統(tǒng)中存在,可以由任何進(jìn)程打開(kāi)和使用。

創(chuàng)建命名管道并寫入數(shù)據(jù):

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>int main() {char *fifo = "/tmp/my_fifo";  // 定義FIFO的路徑// 創(chuàng)建命名管道mkfifo(fifo, 0666);// 打開(kāi)FIFO的寫端int fd = open(fifo, O_WRONLY);char message[] = "Hello from writer!";write(fd, message, strlen(message) + 1);  // 寫入數(shù)據(jù)到FIFOclose(fd);  // 關(guān)閉FIFOreturn 0;
}

運(yùn)行結(jié)果:

光標(biāo)一直閃爍,等待被消費(fèi)。

讀取命名管道中的數(shù)據(jù):

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main() {char *fifo = "/tmp/my_fifo";  // 定義FIFO的路徑char buffer[100];// 打開(kāi)FIFO的讀端int fd = open(fifo, O_RDONLY);read(fd, buffer, sizeof(buffer));  // 從FIFO中讀取數(shù)據(jù)printf("Reader process received: %s\n", buffer);close(fd);  // 關(guān)閉FIFO// 刪除命名管道文件unlink(fifo);return 0;
}

運(yùn)行結(jié)果:

Reader process received: Hello from writer!

解釋:

  • 需要編譯兩個(gè)文件,打開(kāi)兩個(gè)終端編譯運(yùn)行兩個(gè)不同的代碼文件,一個(gè)生產(chǎn),一個(gè)消費(fèi)。

  • 一個(gè)進(jìn)程通過(guò)打開(kāi)命名管道的寫端來(lái)發(fā)送數(shù)據(jù),另一個(gè)進(jìn)程通過(guò)打開(kāi)命名管道的讀端來(lái)接收數(shù)據(jù)。

  • 讀完數(shù)據(jù)后,使用 unlink(fifo) 刪除命名管道文件

4.2 消息隊(duì)列(Message Queue)

消息隊(duì)列是一種進(jìn)程間通信(IPC)機(jī)制,允許進(jìn)程通過(guò)消息的形式進(jìn)行異步通信。與管道不同,消息隊(duì)列支持有序存儲(chǔ)消息,并允許進(jìn)程以不同的優(yōu)先級(jí)發(fā)送和接收消息。消息隊(duì)列是持久的,即使創(chuàng)建消息隊(duì)列的進(jìn)程退出,消息隊(duì)列仍然存在,直到顯式刪除為止。

以下是包含操作說(shuō)明的消息隊(duì)列操作表格:

函數(shù)參數(shù)參數(shù)描述操作返回值
msgget()key消息隊(duì)列的鍵值,唯一標(biāo)識(shí)消息隊(duì)列。創(chuàng)建或獲取消息隊(duì)列成功時(shí)返回消息隊(duì)列標(biāo)識(shí)符,失敗時(shí)返回 -1
msgflg標(biāo)志位,用于設(shè)置權(quán)限和操作選項(xiàng),如 IPC_CREAT 表示創(chuàng)建消息隊(duì)列。
msgsnd()msqid消息隊(duì)列標(biāo)識(shí)符(通過(guò) msgget() 獲取)。向消息隊(duì)列發(fā)送消息成功時(shí)返回 0,失敗時(shí)返回 -1
msgp指向消息結(jié)構(gòu)的指針,包含消息類型和消息正文。
msgsz消息正文的大小。
msgflg控制操作的標(biāo)志位,如 IPC_NOWAIT 表示非阻塞發(fā)送。
msgrcv()msqid消息隊(duì)列標(biāo)識(shí)符。從消息隊(duì)列接收消息成功時(shí)返回接收到的消息大小,失敗時(shí)返回 -1
msgp指向存儲(chǔ)接收到消息的結(jié)構(gòu)的指針。
msgsz消息正文的大小。
msgtyp指定要接收的消息類型,0 表示接收隊(duì)列中的第一個(gè)消息。
msgflg控制操作的標(biāo)志位,如 IPC_NOWAIT 表示非阻塞接收。
msgctl()msqid消息隊(duì)列標(biāo)識(shí)符。控制消息隊(duì)列操作成功時(shí)返回 0,失敗時(shí)返回 -1
cmd指定要執(zhí)行的操作,如 IPC_RMID 刪除消息隊(duì)列,IPC_STAT 獲取消息隊(duì)列信息。
buf可選參數(shù),用于存儲(chǔ)或傳遞消息隊(duì)列的狀態(tài)信息。

詳細(xì)操作說(shuō)明:

  1. msgget():

    操作: 用于創(chuàng)建一個(gè)新的消息隊(duì)列或獲取一個(gè)現(xiàn)有的消息隊(duì)列。

    典型用法: 如果消息隊(duì)列不存在且設(shè)置了 IPC_CREAT 標(biāo)志,則會(huì)創(chuàng)建一個(gè)新的消息隊(duì)列。否則,返回現(xiàn)有的消息隊(duì)列標(biāo)識(shí)符。

  2. msgsnd():

    操作: 將消息發(fā)送到指定的消息隊(duì)列中。

    典型用法: 將消息結(jié)構(gòu) msgp 中的消息添加到 msqid 標(biāo)識(shí)的隊(duì)列中。如果設(shè)置了 IPC_NOWAIT,則在隊(duì)列已滿時(shí)不會(huì)阻塞。

  3. msgrcv():

    操作: 從指定的消息隊(duì)列中接收消息。

    典型用法: 從 msqid 標(biāo)識(shí)的隊(duì)列中接收消息,并將其存儲(chǔ)在 msgp 指向的結(jié)構(gòu)中。如果 msgtyp0,接收隊(duì)列中的第一個(gè)消息;如果 msgtyp 為正數(shù),接收該類型的消息。

  4. msgctl():

    操作: 執(zhí)行消息隊(duì)列的控制操作,例如刪除消息隊(duì)列或查詢隊(duì)列的狀態(tài)。

    典型用法: 使用 IPC_RMID 標(biāo)志刪除消息隊(duì)列,或使用 IPC_STAT 獲取隊(duì)列的狀態(tài)信息。

發(fā)送消息的程序(sender.c)

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>#define MAX 100// 定義消息結(jié)構(gòu)
struct mesg_buffer {long mesg_type;char mesg_text[MAX];
} message;int main() {key_t key;int msgid;// 生成唯一的鍵key = ftok("progfile", 65);// 創(chuàng)建消息隊(duì)列并返回標(biāo)識(shí)符msgid = msgget(key, 0666 | IPC_CREAT);// 消息類型設(shè)為 1message.mesg_type = 1;while(1) {printf("Enter a message to send: ");fgets(message.mesg_text, MAX, stdin);// 向消息隊(duì)列發(fā)送消息msgsnd(msgid, &message, sizeof(message), 0);// 如果輸入 "exit",結(jié)束聊天if (strncmp(message.mesg_text, "exit", 4) == 0) {break;}}return 0;
}

運(yùn)行結(jié)果:

liber@liber-VMware-Virtual-Platform:/home/c$ gcc sender.c -o sender
liber@liber-VMware-Virtual-Platform:/home/c$ ./sender
Enter a message to send: hello
Enter a message to send: exit

解釋:

  • msgget()用于創(chuàng)建或獲取消息隊(duì)列。使用 ftok() 函數(shù)生成一個(gè)唯一的鍵值,用于標(biāo)識(shí)消息隊(duì)列。

  • msgsnd()sender 程序中用于發(fā)送消息。消息類型設(shè)置為 1,消息內(nèi)容通過(guò)用戶輸入獲取。

接收消息的程序(receiver.c)

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>#define MAX 100// 定義消息結(jié)構(gòu)
struct mesg_buffer {long mesg_type;char mesg_text[MAX];
} message;int main() {key_t key;int msgid;// 生成唯一的鍵key = ftok("progfile", 65);// 創(chuàng)建消息隊(duì)列并返回標(biāo)識(shí)符msgid = msgget(key, 0666 | IPC_CREAT);while(1) {// 從消息隊(duì)列中接收消息msgrcv(msgid, &message, sizeof(message), 1, 0);printf("Received message: %s", message.mesg_text);// 如果接收到 "exit",結(jié)束聊天if (strncmp(message.mesg_text, "exit", 4) == 0) {// 刪除消息隊(duì)列msgctl(msgid, IPC_RMID, NULL);break;}}return 0;
}

運(yùn)行結(jié)果:

liber@liber-VMware-Virtual-Platform:/home/c$ gcc receiver.c -o receiver
liber@liber-VMware-Virtual-Platform:/home/c$ ./receiver
Received message: hello
Received message: exit

解釋:

  • msgrcv()receiver 程序中用于接收消息。它會(huì)阻塞,直到接收到類型為 1 的消息。
  • msgctl()當(dāng)接收到的消息內(nèi)容為 "exit" 時(shí),使用 msgctl() 函數(shù)刪除消息隊(duì)列,清理 IPC 資源。

4.3共享內(nèi)存(Shared Memory)

共享內(nèi)存是一種高效的進(jìn)程間通信(IPC)機(jī)制,允許多個(gè)進(jìn)程直接訪問(wèn)同一塊內(nèi)存區(qū)域,從而實(shí)現(xiàn)數(shù)據(jù)的快速共享和交換。共享內(nèi)存是所有 IPC 機(jī)制中最快的一種,因?yàn)閿?shù)據(jù)不需要在進(jìn)程之間復(fù)制,而是所有參與的進(jìn)程可以直接訪問(wèn)同一片物理內(nèi)存,以下是共享內(nèi)存操作的基本函數(shù)及其用途。

函數(shù)參數(shù)操作描述
shmget()key: 共享內(nèi)存段的唯一標(biāo)識(shí)符,通常由 ftok() 生成。創(chuàng)建或獲取共享內(nèi)存段創(chuàng)建或獲取共享內(nèi)存段,并返回一個(gè)標(biāo)識(shí)符(shmid)。如果內(nèi)存段不存在且設(shè)置了 IPC_CREAT,則創(chuàng)建一個(gè)新的共享內(nèi)存段。
size: 共享內(nèi)存段的大小(以字節(jié)為單位)。
shmflg: 標(biāo)志位,常用值包括 IPC_CREAT 用于創(chuàng)建新內(nèi)存段,0666 設(shè)置權(quán)限。
shmat()shmid: 共享內(nèi)存段的標(biāo)識(shí)符,由 shmget() 返回。附加共享內(nèi)存段到進(jìn)程的地址空間將共享內(nèi)存段附加到當(dāng)前進(jìn)程的地址空間中,使得進(jìn)程可以訪問(wèn)該內(nèi)存。返回一個(gè)指向共享內(nèi)存的指針。
shmaddr: 附加到的內(nèi)存地址,通常為 NULL 讓系統(tǒng)自動(dòng)選擇地址。
shmflg: 操作標(biāo)志位,通常為 0(讀寫),也可以設(shè)置為 SHM_RDONLY 只讀。
shmdt()shmaddr: 要分離的共享內(nèi)存段的地址,必須是 shmat() 返回的地址。從進(jìn)程的地址空間分離共享內(nèi)存段將共享內(nèi)存段從當(dāng)前進(jìn)程的地址空間分離,之后進(jìn)程不能再訪問(wèn)該內(nèi)存。
shmctl()shmid: 共享內(nèi)存段的標(biāo)識(shí)符。控制共享內(nèi)存段控制共享內(nèi)存段的行為,例如刪除共享內(nèi)存段以釋放系統(tǒng)資源,或者獲取共享內(nèi)存段的狀態(tài)信息。
cmd: 控制命令,如 IPC_RMID(刪除共享內(nèi)存段)或 IPC_STAT(獲取狀態(tài)信息)。
buf: 一個(gè) struct shmid_ds 類型的緩沖區(qū),用于存儲(chǔ)或傳遞內(nèi)存段的狀態(tài)信息。

寫入共享內(nèi)存:

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>int main() {// 生成唯一的鍵值key_t key = ftok("shmfile", 65);// 創(chuàng)建共享內(nèi)存段,返回標(biāo)識(shí)符int shmid = shmget(key, 1024, 0666 | IPC_CREAT);// 將共享內(nèi)存段附加到進(jìn)程的地址空間char *str = (char*) shmat(shmid, (void*)0, 0);// 向共享內(nèi)存寫入數(shù)據(jù)strcpy(str, "Hello from Process A!");printf("Data written to shared memory: %s\n", str);// 分離共享內(nèi)存段shmdt(str);return 0;
}

運(yùn)行結(jié)果:

Data written to shared memory: Hello from Process A!

解釋:

**shmget()**創(chuàng)建或獲取一個(gè)共享內(nèi)存段,大小為 1024 字節(jié)。IPC_CREAT 標(biāo)志表示如果共享內(nèi)存段不存在則創(chuàng)建它。

**shmat()**將共享內(nèi)存段附加到進(jìn)程的地址空間,使得進(jìn)程可以訪問(wèn)該內(nèi)存。返回一個(gè)指向該內(nèi)存段的指針。

讀取共享內(nèi)存:

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>int main() {// 生成與進(jìn)程 A 相同的鍵值key_t key = ftok("shmfile", 65);// 獲取共享內(nèi)存段的標(biāo)識(shí)符int shmid = shmget(key, 1024, 0666);// 將共享內(nèi)存段附加到進(jìn)程的地址空間char *str = (char*) shmat(shmid, (void*)0, 0);// 讀取共享內(nèi)存中的數(shù)據(jù)printf("Data read from shared memory: %s\n", str);// 分離共享內(nèi)存段shmdt(str);// 刪除共享內(nèi)存段shmctl(shmid, IPC_RMID, NULL);return 0;
}

運(yùn)行結(jié)果:

Data read from shared memory: Hello from Process A!

解釋:

**shmdt()**從進(jìn)程的地址空間分離共享內(nèi)存段。

**shmctl()**刪除共享內(nèi)存段,釋放資源。

4.4 信號(hào)量(Semaphores)

信號(hào)量是一種用于進(jìn)程或線程間同步的機(jī)制,用來(lái)控制對(duì)共享資源的訪問(wèn)。信號(hào)量通過(guò)維護(hù)一個(gè)計(jì)數(shù)器來(lái)控制多個(gè)進(jìn)程或線程對(duì)臨界資源的訪問(wèn)。信號(hào)量可以用于解決競(jìng)態(tài)條件問(wèn)題,確保多個(gè)進(jìn)程或線程在并發(fā)訪問(wèn)共享資源時(shí)不會(huì)產(chǎn)生沖突。

函數(shù)參數(shù)參數(shù)描述操作描述
sem_init()sem指向信號(hào)量對(duì)象的指針,用于初始化信號(hào)量。初始化信號(hào)量初始化一個(gè)信號(hào)量,設(shè)置其初始值。根據(jù) pshared 的值決定信號(hào)量用于線程間同步還是進(jìn)程間共享。
pshared指定信號(hào)量的作用范圍,0信號(hào)量用于線程間同步,非 0信號(hào)量在進(jìn)程間共享。
value設(shè)置信號(hào)量的初始值,表示資源的初始可用數(shù)量。
sem_wait()sem指向信號(hào)量對(duì)象的指針,表示要等待的信號(hào)量。等待信號(hào)量執(zhí)行 P 操作。如果信號(hào)量值大于 0,信號(hào)量值減 1 并繼續(xù)執(zhí)行;如果信號(hào)量值為 0,則阻塞,直到信號(hào)量值大于 0。
sem_post()sem指向信號(hào)量對(duì)象的指針,表示要釋放的信號(hào)量。釋放信號(hào)量執(zhí)行 V 操作。將信號(hào)量的值加 1,如果有進(jìn)程或線程在等待該信號(hào)量,則喚醒其中一個(gè)。
sem_destroy()sem指向信號(hào)量對(duì)象的指針,用于銷毀信號(hào)量。銷毀信號(hào)量銷毀信號(hào)量并釋放與其相關(guān)的資源。僅適用于未用于進(jìn)程間共享的信號(hào)量。

使用信號(hào)量同步兩個(gè)線程:

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>sem_t sem;void* thread_func1(void* arg) {printf("Thread 1: Waiting for semaphore...\n");sem_wait(&sem);  // 等待信號(hào)量printf("Thread 1: Inside critical section.\n");sem_post(&sem);  // 釋放信號(hào)量return NULL;
}void* thread_func2(void* arg) {printf("Thread 2: Waiting for semaphore...\n");sem_wait(&sem);  // 等待信號(hào)量printf("Thread 2: Inside critical section.\n");sem_post(&sem);  // 釋放信號(hào)量return NULL;
}int main() {pthread_t t1, t2;// 初始化信號(hào)量,初始值為 1sem_init(&sem, 0, 1);// 創(chuàng)建兩個(gè)線程pthread_create(&t1, NULL, thread_func1, NULL);pthread_create(&t2, NULL, thread_func2, NULL);// 等待兩個(gè)線程完成pthread_join(t1, NULL);pthread_join(t2, NULL);// 銷毀信號(hào)量sem_destroy(&sem);return 0;
}

liber@liber-VMware-Virtual-Platform:/home/c$ ./receiver
Thread 1: Waiting for semaphore…
Thread 1: Inside critical section.
Thread 2: Waiting for semaphore…
Thread 2: Inside critical section.
liber@liber-VMware-Virtual-Platform:/home/c$ ./receiver
Thread 1: Waiting for semaphore…
Thread 2: Waiting for semaphore…
Thread 2: Inside critical section.
Thread 1: Inside critical section.
liber@liber-VMware-Virtual-Platform:/home/c$ ./receiver
Thread 2: Waiting for semaphore…
Thread 2: Inside critical section.
Thread 1: Waiting for semaphore…
Thread 1: Inside critical section.

解釋:

  • **sem_init()**初始化信號(hào)量 sem,初始值設(shè)置為 1,表示資源最開(kāi)始是可用的。第二個(gè)參數(shù)為 0,表示這是一個(gè)線程級(jí)別的信號(hào)量。

  • **sem_wait()**在每個(gè)線程的臨界區(qū)(Critical Section)前調(diào)用 sem_wait(),等待信號(hào)量。如果信號(hào)量值為 1,則進(jìn)入臨界區(qū)并將信號(hào)量值減為 0;如果信號(hào)量值為 0,線程將阻塞,直到信號(hào)量變?yōu)?1。

  • **sem_post()**在臨界區(qū)操作完成后調(diào)用 sem_post(),釋放信號(hào)量,將信號(hào)量值加 1。如果有其他線程在等待信號(hào)量,它們將被喚醒。

  • **sem_destroy()**在程序結(jié)束時(shí),銷毀信號(hào)量 sem,釋放其相關(guān)的資源。

  • 信號(hào)量在這個(gè)程序中確實(shí)起到了同步的作用,確保了同時(shí)只有一個(gè)線程可以進(jìn)入臨界區(qū)(信號(hào)量值為 1 時(shí),只有一個(gè)線程可以繼續(xù),另一個(gè)線程必須等待)

具體的同步過(guò)程:

  • 通過(guò)使用信號(hào)量(sem_t sem),確保兩個(gè)線程不會(huì)同時(shí)進(jìn)入臨界區(qū)(即 thread_func1thread_func2 中的代碼塊 printf("Inside critical section.\n");

  • 信號(hào)量通過(guò)阻塞和喚醒機(jī)制協(xié)調(diào)多個(gè)線程的執(zhí)行順序。例如,當(dāng) sem_wait(&sem) 在一個(gè)線程中被調(diào)用時(shí),如果信號(hào)量的值為 0,該線程將被阻塞,直到另一個(gè)線程調(diào)用 sem_post(&sem) 釋放信號(hào)量。

  • 當(dāng) thread_func1thread_func2 開(kāi)始執(zhí)行時(shí),它們都會(huì)調(diào)用 sem_wait(&sem)。此時(shí),信號(hào)量的初始值為 1,表示資源(即進(jìn)入臨界區(qū)的權(quán)限)是可用的。

  • 假設(shè) thread_func1 先調(diào)用 sem_wait(&sem),信號(hào)量值減為 0,thread_func1 進(jìn)入臨界區(qū)。thread_func2 此時(shí)如果調(diào)用 sem_wait(&sem),因?yàn)樾盘?hào)量值已經(jīng)是 0,它將被阻塞,直到 thread_func1 調(diào)用 sem_post(&sem) 釋放信號(hào)量。

  • thread_func1 退出臨界區(qū)后調(diào)用 sem_post(&sem),信號(hào)量值重新變?yōu)?1,系統(tǒng)將喚醒 thread_func2,允許它進(jìn)入臨界區(qū)。

5. 進(jìn)程的信號(hào)處理

進(jìn)程的信號(hào)處理是指在操作系統(tǒng)中,進(jìn)程對(duì)信號(hào)(Signal)的接收和響應(yīng)方式。信號(hào)是一種異步的進(jìn)程間通信方式,通常用于通知進(jìn)程發(fā)生了某種事件,如終止、暫停、繼續(xù)執(zhí)行或捕獲某些異常情況。進(jìn)程可以通過(guò)定義信號(hào)處理程序來(lái)響應(yīng)特定的信號(hào),執(zhí)行相應(yīng)的處理邏輯。

5.1 常見(jiàn)信號(hào)及默認(rèn)行為

信號(hào)描述默認(rèn)行為
SIGINT終端中斷信號(hào),用戶按 Ctrl+C 觸發(fā)終止進(jìn)程
SIGTERM請(qǐng)求進(jìn)程終止,允許進(jìn)程進(jìn)行清理工作終止進(jìn)程
SIGKILL強(qiáng)制終止進(jìn)程,無(wú)法被捕獲或忽略強(qiáng)制終止進(jìn)程
SIGCHLD子進(jìn)程狀態(tài)改變(如退出或停止)忽略
SIGHUP終端掛起或控制終端關(guān)閉時(shí)發(fā)送,通常用于通知守護(hù)進(jìn)程重新加載配置文件終止進(jìn)程
SIGQUIT從終端發(fā)出的退出信號(hào)(通常是 Ctrl+\),會(huì)生成核心轉(zhuǎn)儲(chǔ)生成核心轉(zhuǎn)儲(chǔ)并終止進(jìn)程
SIGILL非法指令執(zhí)行,如執(zhí)行未定義的機(jī)器指令生成核心轉(zhuǎn)儲(chǔ)并終止進(jìn)程
SIGABRT調(diào)用 abort() 函數(shù)引發(fā)的信號(hào),表示進(jìn)程異常終止生成核心轉(zhuǎn)儲(chǔ)并終止進(jìn)程
SIGFPE算術(shù)運(yùn)算錯(cuò)誤(如除以零或溢出),浮點(diǎn)異常生成核心轉(zhuǎn)儲(chǔ)并終止進(jìn)程
SIGSEGV段錯(cuò)誤,非法內(nèi)存訪問(wèn)生成核心轉(zhuǎn)儲(chǔ)并終止進(jìn)程
SIGPIPE向無(wú)讀者的管道寫數(shù)據(jù)時(shí)引發(fā),通常在管道通信中出現(xiàn)終止進(jìn)程
SIGBUS總線錯(cuò)誤,非法內(nèi)存訪問(wèn)(如未對(duì)齊的內(nèi)存訪問(wèn))生成核心轉(zhuǎn)儲(chǔ)并終止進(jìn)程
SIGALRMalarm() 函數(shù)觸發(fā)的定時(shí)信號(hào)終止進(jìn)程
SIGUSR1用戶自定義信號(hào) 1終止進(jìn)程(用戶可定義處理行為)
SIGUSR2用戶自定義信號(hào) 2終止進(jìn)程(用戶可定義處理行為)
SIGTRAP斷點(diǎn)陷阱,用于調(diào)試,通常由調(diào)試器捕獲生成核心轉(zhuǎn)儲(chǔ)并終止進(jìn)程
SIGURG緊急情況(out-of-band data)到達(dá)套接字忽略
SIGXCPU超出 CPU 時(shí)間限制生成核心轉(zhuǎn)儲(chǔ)并終止進(jìn)程
SIGXFSZ超出文件大小限制生成核心轉(zhuǎn)儲(chǔ)并終止進(jìn)程
SIGVTALRM虛擬計(jì)時(shí)器到期,通常用于跟蹤用戶時(shí)間消耗終止進(jìn)程
SIGPROF計(jì)時(shí)器到期,通常用于統(tǒng)計(jì)進(jìn)程的 CPU 使用情況終止進(jìn)程
SIGWINCH終端窗口大小改變忽略
SIGTSTP終端停止信號(hào),用戶按 Ctrl+Z 觸發(fā),暫停進(jìn)程停止進(jìn)程
SIGCONT繼續(xù)執(zhí)行已停止的進(jìn)程繼續(xù)執(zhí)行(如果之前停止,則恢復(fù)執(zhí)行)
SIGSTOP停止進(jìn)程,無(wú)法捕獲或忽略停止進(jìn)程
SIGTTIN后臺(tái)進(jìn)程組試圖從終端讀取數(shù)據(jù)時(shí)引發(fā)的信號(hào)停止進(jìn)程
SIGTTOU后臺(tái)進(jìn)程組試圖向終端寫數(shù)據(jù)時(shí)引發(fā)的信號(hào)停止進(jìn)程

5.2 信號(hào)處理函數(shù)

函數(shù)參數(shù)參數(shù)描述用途描述
signal()signum要處理的信號(hào)編號(hào),如 SIGINT注冊(cè)簡(jiǎn)單的信號(hào)處理程序用于指定一個(gè)信號(hào)處理函數(shù),當(dāng)進(jìn)程接收到特定信號(hào)時(shí)執(zhí)行。
handler信號(hào)處理函數(shù)的指針,或特殊值 SIG_IGN(忽略信號(hào))和 SIG_DFL(默認(rèn)處理)
sigaction()signum要處理的信號(hào)編號(hào),如 SIGINT注冊(cè)信號(hào)處理程序,替代 signalsigactionsignal 的增強(qiáng)版本,允許更詳細(xì)地控制信號(hào)處理行為。
act包含新信號(hào)處理動(dòng)作的 struct sigaction 結(jié)構(gòu)的指針
oldact保存先前信號(hào)處理設(shè)置的 struct sigaction 結(jié)構(gòu)的指針
sigprocmask()how指定如何修改信號(hào)屏蔽字的操作,如 SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK改變信號(hào)屏蔽字,阻塞或解除阻塞信號(hào)用于檢查和更改進(jìn)程的信號(hào)屏蔽字,可以阻塞或解除阻塞某些信號(hào)。
set新的信號(hào)屏蔽字,表示要阻塞的信號(hào)
oldset保存先前信號(hào)屏蔽字的指針
sigpending()set存儲(chǔ)當(dāng)前掛起信號(hào)的信號(hào)集的指針檢查當(dāng)前掛起的信號(hào)檢查進(jìn)程當(dāng)前掛起的信號(hào)集,即那些已經(jīng)發(fā)送但因被阻塞而未處理的信號(hào)。
sigsuspend()mask新的信號(hào)屏蔽字,用于臨時(shí)替換當(dāng)前信號(hào)屏蔽字臨時(shí)替換信號(hào)屏蔽字并掛起進(jìn)程,等待特定信號(hào)替換信號(hào)屏蔽字并掛起進(jìn)程執(zhí)行,直到接收到一個(gè)未被屏蔽的信號(hào)。
raise()sig要發(fā)送的信號(hào)編號(hào)向當(dāng)前進(jìn)程發(fā)送信號(hào)用于在當(dāng)前進(jìn)程中發(fā)送信號(hào),相當(dāng)于在進(jìn)程內(nèi)部自發(fā)生成一個(gè)信號(hào)。
kill()pid目標(biāo)進(jìn)程的進(jìn)程 ID向指定進(jìn)程發(fā)送信號(hào)向指定的進(jìn)程發(fā)送信號(hào),可以發(fā)送任何信號(hào),而不僅僅是 SIGKILL。
sig要發(fā)送的信號(hào)編號(hào)
pause()無(wú)無(wú)掛起進(jìn)程執(zhí)行,直到接收到一個(gè)信號(hào)掛起進(jìn)程的執(zhí)行,直到收到并處理一個(gè)信號(hào)。

簡(jiǎn)單案例

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>// 信號(hào)處理函數(shù)
void handle_signal(int sig) {switch (sig) {case SIGINT:printf("Caught SIGINT (Ctrl+C), but not terminating the process.\n");break;case SIGTERM:printf("Caught SIGTERM, terminating the process.\n");exit(0);break;case SIGCHLD:printf("Caught SIGCHLD, cleaning up child process.\n");wait(NULL);  // 清理子進(jìn)程break;case SIGHUP:printf("Caught SIGHUP, reloading configuration...\n");// 模擬重新加載配置break;case SIGQUIT:printf("Caught SIGQUIT (Ctrl+\\), generating core dump.\n");abort();  // 生成核心轉(zhuǎn)儲(chǔ)并終止進(jìn)程break;default:printf("Caught signal %d, no specific handler defined.\n", sig);}
}int main() {// 使用 signal() 注冊(cè)信號(hào)處理函數(shù)signal(SIGINT, handle_signal);signal(SIGTERM, handle_signal);signal(SIGCHLD, handle_signal);signal(SIGHUP, handle_signal);signal(SIGQUIT, handle_signal);// 創(chuàng)建一個(gè)子進(jìn)程來(lái)演示 SIGCHLDif (fork() == 0) {printf("Child process started, will terminate in 5 seconds...\n");sleep(5);exit(0);}// 模擬守護(hù)進(jìn)程的運(yùn)行while (1) {printf("Running... (PID: %d)\n", getpid());sleep(2);  // 模擬長(zhǎng)期運(yùn)行的進(jìn)程}return 0;
}

如何運(yùn)行和測(cè)試:

  • Ctrl+C:觸發(fā) SIGINT 信號(hào),處理函數(shù)會(huì)打印一條消息,但進(jìn)程不會(huì)終止。
  • 發(fā)送 SIGTERM:可以通過(guò)命令 kill -SIGTERM <PID> 發(fā)送 SIGTERM 信號(hào),處理函數(shù)會(huì)終止進(jìn)程。
  • Ctrl+\:觸發(fā) SIGQUIT 信號(hào),處理函數(shù)會(huì)生成核心轉(zhuǎn)儲(chǔ)文件并終止進(jìn)程。
  • 發(fā)送 SIGHUP:可以通過(guò)命令 kill -SIGHUP <PID> 發(fā)送 SIGHUP 信號(hào),處理函數(shù)會(huì)模擬重新加載配置文件。
  • 等待子進(jìn)程終止:子進(jìn)程終止時(shí),父進(jìn)程捕獲 SIGCHLD 信號(hào)并清理子進(jìn)程。

運(yùn)行結(jié)果:

第一個(gè)終端:

Running… (PID: 1933357)
Child process started, will terminate in 5 seconds…
^CCaught SIGINT (Ctrl+C), but not terminating the process.
Caught SIGINT (Ctrl+C), but not terminating the process.
Running… (PID: 1933357)
Caught SIGCHLD, cleaning up child process.
Running… (PID: 1933357)
Caught SIGHUP, reloading configuration…
Running… (PID: 1933357)
Caught SIGTERM, terminating the process.

第二個(gè)終端:

liber@liber-VMware-Virtual-Platform:~$ kill -SIGHUP 1933357
liber@liber-VMware-Virtual-Platform:~$ kill -SIGTERM 1933357

6 常見(jiàn)的進(jìn)程調(diào)度算法

6.1 先來(lái)先服務(wù)調(diào)度(FCFS, First-Come, First-Served)

先來(lái)先服務(wù)調(diào)度是一種最簡(jiǎn)單的調(diào)度算法。進(jìn)程按照它們到達(dá)就緒隊(duì)列的順序依次運(yùn)行,先到達(dá)的進(jìn)程先執(zhí)行,后到達(dá)的進(jìn)程后執(zhí)行。這個(gè)算法使用一個(gè)FIFO(First In, First Out)隊(duì)列來(lái)管理進(jìn)程順序。

#include <stdio.h>// 定義進(jìn)程結(jié)構(gòu)體,用來(lái)保存每個(gè)進(jìn)程的相關(guān)信息
struct Process {int pid;            // 進(jìn)程IDint arrival_time;   // 到達(dá)時(shí)間int burst_time;     // 執(zhí)行時(shí)間(運(yùn)行所需時(shí)間)int completion_time;// 完成時(shí)間(進(jìn)程完成執(zhí)行的時(shí)間點(diǎn))int waiting_time;   // 等待時(shí)間(進(jìn)程在就緒隊(duì)列中等待的時(shí)間)int turnaround_time;// 周轉(zhuǎn)時(shí)間(從到達(dá)到完成所用的總時(shí)間)
};// FCFS調(diào)度算法的實(shí)現(xiàn)
void fcfs_scheduling(struct Process processes[], int n) {int current_time = 0;  // 用于跟蹤當(dāng)前時(shí)間進(jìn)度// 按照到達(dá)時(shí)間對(duì)進(jìn)程排序,以確保先到的進(jìn)程先執(zhí)行for (int i = 0; i < n; i++) {// 如果當(dāng)前時(shí)間小于進(jìn)程的到達(dá)時(shí)間,CPU需要空閑等待if (current_time < processes[i].arrival_time) {current_time = processes[i].arrival_time;}// 計(jì)算進(jìn)程的完成時(shí)間processes[i].completion_time = current_time + processes[i].burst_time;// 計(jì)算周轉(zhuǎn)時(shí)間 = 完成時(shí)間 - 到達(dá)時(shí)間processes[i].turnaround_time = processes[i].completion_time - processes[i].arrival_time;// 計(jì)算等待時(shí)間 = 周轉(zhuǎn)時(shí)間 - 執(zhí)行時(shí)間processes[i].waiting_time = processes[i].turnaround_time - processes[i].burst_time;// 更新當(dāng)前時(shí)間為此進(jìn)程的完成時(shí)間current_time = processes[i].completion_time;}
}// 打印所有進(jìn)程的信息,包括PID、到達(dá)時(shí)間、執(zhí)行時(shí)間、完成時(shí)間、等待時(shí)間、和周轉(zhuǎn)時(shí)間
void print_processes(struct Process processes[], int n) {printf("PID\tArrival\tBurst\tCompletion\tWaiting\tTurnaround\n");for (int i = 0; i < n; i++) {printf("%d\t%d\t%d\t%d\t\t%d\t%d\n",processes[i].pid,processes[i].arrival_time,processes[i].burst_time,processes[i].completion_time,processes[i].waiting_time,processes[i].turnaround_time);}
}int main() {int n;  // 進(jìn)程數(shù)量// 用戶輸入進(jìn)程的數(shù)量printf("輸入進(jìn)程數(shù)量: ");scanf("%d", &n);struct Process processes[n];  // 創(chuàng)建進(jìn)程數(shù)組// 用戶輸入每個(gè)進(jìn)程的到達(dá)時(shí)間和執(zhí)行時(shí)間for (int i = 0; i < n; i++) {printf("輸入進(jìn)程 %d 的到達(dá)時(shí)間和執(zhí)行時(shí)間: ", i + 1);scanf("%d %d", &processes[i].arrival_time, &processes[i].burst_time);processes[i].pid = i + 1;  // 進(jìn)程ID從1開(kāi)始}// 調(diào)用FCFS調(diào)度算法fcfs_scheduling(processes, n);// 打印調(diào)度結(jié)果print_processes(processes, n);return 0;
}

運(yùn)行結(jié)果:

輸入進(jìn)程數(shù)量: 5
輸入進(jìn)程 1 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 1 1
輸入進(jìn)程 2 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 2 2
輸入進(jìn)程 3 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 3 3
輸入進(jìn)程 4 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 4 4
輸入進(jìn)程 5 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 5 5
PID Arrival Burst Completion Waiting Turnaround
1 1 1 2 0 1
2 2 2 4 0 2
3 3 3 7 1 4
4 4 4 11 3 7
5 5 5 16 6 11

6.2 短作業(yè)優(yōu)先調(diào)度(SJF, Shortest Job First)

短作業(yè)優(yōu)先調(diào)度是一種非搶占式調(diào)度算法。每次選擇執(zhí)行時(shí)間(即“作業(yè)長(zhǎng)度”)最短的進(jìn)程進(jìn)行調(diào)度。它可以降低平均等待時(shí)間,因?yàn)槎套鳂I(yè)可以盡快完成,減少后續(xù)作業(yè)的等待時(shí)間。

需要注意的是,SJF算法需要知道每個(gè)作業(yè)的執(zhí)行時(shí)間(burst time),但在實(shí)際系統(tǒng)中,這通常是未知的,所以SJF在實(shí)際中主要作為理論模型或通過(guò)預(yù)測(cè)實(shí)現(xiàn)。

#include <stdio.h>
#include <limits.h>  // 用于獲取整型的最大值(INT_MAX)// 定義進(jìn)程結(jié)構(gòu)體
struct Process {int pid;            // 進(jìn)程IDint arrival_time;   // 到達(dá)時(shí)間int burst_time;     // 執(zhí)行時(shí)間(運(yùn)行所需時(shí)間)int completion_time;// 完成時(shí)間int waiting_time;   // 等待時(shí)間int turnaround_time;// 周轉(zhuǎn)時(shí)間int is_completed;   // 標(biāo)記進(jìn)程是否已完成
};// SJF調(diào)度算法的實(shí)現(xiàn)
void sjf_scheduling(struct Process processes[], int n) {int completed = 0;       // 已完成的進(jìn)程數(shù)int current_time = 0;     // 當(dāng)前時(shí)間// 當(dāng)所有進(jìn)程都未完成時(shí),繼續(xù)調(diào)度while (completed != n) {int shortest_index = -1;          // 保存最短作業(yè)的索引int shortest_burst = INT_MAX;     // 保存最短作業(yè)的執(zhí)行時(shí)間,初始值設(shè)為最大整數(shù)// 尋找當(dāng)前時(shí)間點(diǎn)上未完成的最短作業(yè)for (int i = 0; i < n; i++) {// 條件:進(jìn)程已經(jīng)到達(dá)、未完成、并且執(zhí)行時(shí)間最短if (processes[i].arrival_time <= current_time && !processes[i].is_completed) {if (processes[i].burst_time < shortest_burst) {shortest_burst = processes[i].burst_time;shortest_index = i; // 記錄該進(jìn)程的索引}}}// 如果找到了合適的作業(yè)(即shortest_index有效)if (shortest_index != -1) {// 1. 將當(dāng)前時(shí)間增加該短作業(yè)的執(zhí)行時(shí)間current_time += processes[shortest_index].burst_time;// 2. 更新該進(jìn)程的完成時(shí)間 = 當(dāng)前時(shí)間processes[shortest_index].completion_time = current_time;// 3. 計(jì)算周轉(zhuǎn)時(shí)間 = 完成時(shí)間 - 到達(dá)時(shí)間processes[shortest_index].turnaround_time = processes[shortest_index].completion_time - processes[shortest_index].arrival_time;// 4. 計(jì)算等待時(shí)間 = 周轉(zhuǎn)時(shí)間 - 執(zhí)行時(shí)間processes[shortest_index].waiting_time = processes[shortest_index].turnaround_time - processes[shortest_index].burst_time;// 5. 將該進(jìn)程標(biāo)記為已完成processes[shortest_index].is_completed = 1;// 6. 更新已完成的進(jìn)程數(shù)completed++;} else {// 如果沒(méi)有合適的作業(yè)可以運(yùn)行,時(shí)間遞增current_time++;}}
}// 打印所有進(jìn)程的信息,包括PID、到達(dá)時(shí)間、執(zhí)行時(shí)間、完成時(shí)間、等待時(shí)間、和周轉(zhuǎn)時(shí)間
void print_processes(struct Process processes[], int n) {printf("PID\tArrival\tBurst\tCompletion\tWaiting\tTurnaround\n");for (int i = 0; i < n; i++) {printf("%d\t%d\t%d\t%d\t\t%d\t%d\n",processes[i].pid,processes[i].arrival_time,processes[i].burst_time,processes[i].completion_time,processes[i].waiting_time,processes[i].turnaround_time);}
}int main() {int n;  // 進(jìn)程數(shù)量// 用戶輸入進(jìn)程的數(shù)量printf("輸入進(jìn)程數(shù)量: ");scanf("%d", &n);struct Process processes[n];  // 創(chuàng)建進(jìn)程數(shù)組// 用戶輸入每個(gè)進(jìn)程的到達(dá)時(shí)間和執(zhí)行時(shí)間for (int i = 0; i < n; i++) {printf("輸入進(jìn)程 %d 的到達(dá)時(shí)間和執(zhí)行時(shí)間: ", i + 1);scanf("%d %d", &processes[i].arrival_time, &processes[i].burst_time);processes[i].pid = i + 1;          // 設(shè)置進(jìn)程IDprocesses[i].is_completed = 0;     // 初始化進(jìn)程為未完成狀態(tài)}// 調(diào)用SJF調(diào)度算法sjf_scheduling(processes, n);// 打印調(diào)度結(jié)果print_processes(processes, n);return 0;
}

運(yùn)行結(jié)果:

輸入進(jìn)程數(shù)量: 5
輸入進(jìn)程 1 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 1 2
輸入進(jìn)程 2 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 1 1
輸入進(jìn)程 3 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 1 4
輸入進(jìn)程 4 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 1 5
輸入進(jìn)程 5 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 1 3
PID Arrival Burst Completion Waiting Turnaround
1 1 2 4 1 3
2 1 1 2 0 1
3 1 4 11 6 10
4 1 5 16 10 15
5 1 3 7 3 6

6.3 最高優(yōu)先級(jí)調(diào)度(Priority Scheduling)

最高優(yōu)先級(jí)調(diào)度是一種調(diào)度策略,進(jìn)程根據(jù)其優(yōu)先級(jí)進(jìn)行調(diào)度,優(yōu)先級(jí)越高的進(jìn)程越早被調(diào)度。該算法可以是搶占式的(高優(yōu)先級(jí)進(jìn)程可以打斷正在運(yùn)行的低優(yōu)先級(jí)進(jìn)程)或非搶占式的(正在運(yùn)行的進(jìn)程不會(huì)被打斷)。

在非搶占式優(yōu)先級(jí)調(diào)度中,當(dāng)前運(yùn)行的進(jìn)程會(huì)一直運(yùn)行至完成,而在搶占式調(diào)度中,當(dāng)一個(gè)高優(yōu)先級(jí)的進(jìn)程到達(dá)時(shí),它會(huì)立即中斷當(dāng)前正在運(yùn)行的低優(yōu)先級(jí)進(jìn)程。

非搶占式優(yōu)先級(jí)調(diào)度:

#include <stdio.h>// 定義進(jìn)程結(jié)構(gòu)體
struct Process {int pid;            // 進(jìn)程IDint arrival_time;   // 到達(dá)時(shí)間int burst_time;     // 執(zhí)行時(shí)間(運(yùn)行所需時(shí)間)int priority;       // 優(yōu)先級(jí)int completion_time;// 完成時(shí)間int waiting_time;   // 等待時(shí)間int turnaround_time;// 周轉(zhuǎn)時(shí)間int is_completed;   // 標(biāo)記進(jìn)程是否已完成
};// 非搶占式優(yōu)先級(jí)調(diào)度算法的實(shí)現(xiàn)
void priority_scheduling(struct Process processes[], int n) {int completed = 0;        // 已完成的進(jìn)程數(shù)int current_time = 0;      // 當(dāng)前時(shí)間// 當(dāng)所有進(jìn)程都未完成時(shí),繼續(xù)調(diào)度while (completed != n) {int highest_priority_index = -1;  // 保存最高優(yōu)先級(jí)進(jìn)程的索引int highest_priority = __INT_MAX__; // 用于比較優(yōu)先級(jí),初始為最大值(數(shù)值越低優(yōu)先級(jí)越高)// 尋找當(dāng)前時(shí)間點(diǎn)上未完成的最高優(yōu)先級(jí)進(jìn)程for (int i = 0; i < n; i++) {if (processes[i].arrival_time <= current_time && !processes[i].is_completed) {if (processes[i].priority < highest_priority) {highest_priority = processes[i].priority;highest_priority_index = i; // 記錄該進(jìn)程的索引}}}// 如果找到了合適的進(jìn)程(即highest_priority_index有效)if (highest_priority_index != -1) {// 1. 將當(dāng)前時(shí)間增加該進(jìn)程的執(zhí)行時(shí)間current_time += processes[highest_priority_index].burst_time;// 2. 更新該進(jìn)程的完成時(shí)間 = 當(dāng)前時(shí)間processes[highest_priority_index].completion_time = current_time;// 3. 計(jì)算周轉(zhuǎn)時(shí)間 = 完成時(shí)間 - 到達(dá)時(shí)間processes[highest_priority_index].turnaround_time = processes[highest_priority_index].completion_time - processes[highest_priority_index].arrival_time;// 4. 計(jì)算等待時(shí)間 = 周轉(zhuǎn)時(shí)間 - 執(zhí)行時(shí)間processes[highest_priority_index].waiting_time = processes[highest_priority_index].turnaround_time - processes[highest_priority_index].burst_time;// 5. 將該進(jìn)程標(biāo)記為已完成processes[highest_priority_index].is_completed = 1;// 6. 更新已完成的進(jìn)程數(shù)completed++;} else {// 如果沒(méi)有合適的進(jìn)程可以運(yùn)行,時(shí)間遞增current_time++;}}
}// 打印所有進(jìn)程的信息,包括PID、到達(dá)時(shí)間、執(zhí)行時(shí)間、優(yōu)先級(jí)、完成時(shí)間、等待時(shí)間和周轉(zhuǎn)時(shí)間
void print_processes(struct Process processes[], int n) {printf("PID\tArrival\tBurst\tPriority\tCompletion\tWaiting\tTurnaround\n");for (int i = 0; i < n; i++) {printf("%d\t%d\t%d\t%d\t\t%d\t\t%d\t%d\n",processes[i].pid,processes[i].arrival_time,processes[i].burst_time,processes[i].priority,processes[i].completion_time,processes[i].waiting_time,processes[i].turnaround_time);}
}int main() {int n;// 用戶輸入進(jìn)程的數(shù)量printf("輸入進(jìn)程數(shù)量: ");scanf("%d", &n);struct Process processes[n];// 用戶輸入每個(gè)進(jìn)程的到達(dá)時(shí)間、執(zhí)行時(shí)間和優(yōu)先級(jí)for (int i = 0; i < n; i++) {printf("輸入進(jìn)程 %d 的到達(dá)時(shí)間、執(zhí)行時(shí)間和優(yōu)先級(jí): ", i + 1);scanf("%d %d %d", &processes[i].arrival_time, &processes[i].burst_time, &processes[i].priority);processes[i].pid = i + 1;          // 設(shè)置進(jìn)程IDprocesses[i].is_completed = 0;     // 初始化進(jìn)程為未完成狀態(tài)}// 調(diào)用優(yōu)先級(jí)調(diào)度算法priority_scheduling(processes, n);// 打印調(diào)度結(jié)果print_processes(processes, n);return 0;
}

運(yùn)行結(jié)果:

輸入進(jìn)程數(shù)量: 3
輸入進(jìn)程 1 的到達(dá)時(shí)間、執(zhí)行時(shí)間和優(yōu)先級(jí): 0 5 2
輸入進(jìn)程 2 的到達(dá)時(shí)間、執(zhí)行時(shí)間和優(yōu)先級(jí): 1 3 1
輸入進(jìn)程 3 的到達(dá)時(shí)間、執(zhí)行時(shí)間和優(yōu)先級(jí): 2 4 3
PID Arrival Burst Priority Completion Waiting Turnaround
1 0 5 2 5 0 5
2 1 3 1 8 4 7
3 2 4 3 12 6 10

說(shuō)明:在非搶占式優(yōu)先級(jí)調(diào)度中,當(dāng)一個(gè)進(jìn)程開(kāi)始執(zhí)行后,即使有更高(本代碼數(shù)字越小,優(yōu)先級(jí)越高)優(yōu)先級(jí)的進(jìn)程到達(dá),也不會(huì)被打斷,直到該進(jìn)程完成。

搶占式優(yōu)先級(jí)調(diào)度:

#include <stdio.h>
#include <limits.h>// 定義進(jìn)程結(jié)構(gòu)體
struct Process {int pid;            // 進(jìn)程IDint arrival_time;   // 到達(dá)時(shí)間int burst_time;     // 執(zhí)行時(shí)間(運(yùn)行所需時(shí)間)int remaining_time; // 剩余執(zhí)行時(shí)間int priority;       // 優(yōu)先級(jí)int completion_time;// 完成時(shí)間int waiting_time;   // 等待時(shí)間int turnaround_time;// 周轉(zhuǎn)時(shí)間
};// 搶占式優(yōu)先級(jí)調(diào)度算法的實(shí)現(xiàn)
void preemptive_priority_scheduling(struct Process processes[], int n) {int current_time = 0;       // 當(dāng)前時(shí)間int completed = 0;          // 已完成的進(jìn)程數(shù)while (completed != n) {int highest_priority_index = -1;int highest_priority = INT_MAX;// 尋找當(dāng)前時(shí)間點(diǎn)上優(yōu)先級(jí)最高且仍未完成的進(jìn)程for (int i = 0; i < n; i++) {if (processes[i].arrival_time <= current_time && processes[i].remaining_time > 0) {if (processes[i].priority < highest_priority) {highest_priority = processes[i].priority;highest_priority_index = i;}}}// 如果找到了合適的進(jìn)程if (highest_priority_index != -1) {// 運(yùn)行該進(jìn)程一個(gè)時(shí)間單位processes[highest_priority_index].remaining_time--;current_time++;// 如果進(jìn)程完成if (processes[highest_priority_index].remaining_time == 0) {completed++;processes[highest_priority_index].completion_time = current_time;processes[highest_priority_index].turnaround_time = processes[highest_priority_index].completion_time - processes[highest_priority_index].arrival_time;processes[highest_priority_index].waiting_time = processes[highest_priority_index].turnaround_time - processes[highest_priority_index].burst_time;}} else {// 如果沒(méi)有進(jìn)程可以運(yùn)行,時(shí)間遞增current_time++;}}
}// 打印所有進(jìn)程的信息,包括PID、到達(dá)時(shí)間、執(zhí)行時(shí)間、優(yōu)先級(jí)、完成時(shí)間、等待時(shí)間和周轉(zhuǎn)時(shí)間
void print_processes(struct Process processes[], int n) {printf("PID\tArrival\tBurst\tPriority\tCompletion\tWaiting\tTurnaround\n");for (int i = 0; i < n; i++) {printf("%d\t%d\t%d\t%d\t\t%d\t\t%d\t%d\n",processes[i].pid,processes[i].arrival_time,processes[i].burst_time,processes[i].priority,processes[i].completion_time,processes[i].waiting_time,processes[i].turnaround_time);}
}int main() {int n;// 用戶輸入進(jìn)程的數(shù)量printf("輸入進(jìn)程數(shù)量: ");scanf("%d", &n);struct Process processes[n];// 用戶輸入每個(gè)進(jìn)程的到達(dá)時(shí)間、執(zhí)行時(shí)間和優(yōu)先級(jí)for (int i = 0; i < n; i++) {printf("輸入進(jìn)程 %d 的到達(dá)時(shí)間、執(zhí)行時(shí)間和優(yōu)先級(jí): ", i + 1);scanf("%d %d %d", &processes[i].arrival_time, &processes[i].burst_time, &processes[i].priority);processes[i].pid = i + 1;                  // 設(shè)置進(jìn)程IDprocesses[i].remaining_time = processes[i].burst_time; // 初始化剩余執(zhí)行時(shí)間}// 調(diào)用搶占式優(yōu)先級(jí)調(diào)度算法preemptive_priority_scheduling(processes, n);// 打印調(diào)度結(jié)果print_processes(processes, n);return 0;
}

運(yùn)行結(jié)果:

輸入進(jìn)程數(shù)量: 3
輸入進(jìn)程 1 的到達(dá)時(shí)間、執(zhí)行時(shí)間和優(yōu)先級(jí): 0 5 2
輸入進(jìn)程 2 的到達(dá)時(shí)間、執(zhí)行時(shí)間和優(yōu)先級(jí): 1 3 1
輸入進(jìn)程 3 的到達(dá)時(shí)間、執(zhí)行時(shí)間和優(yōu)先級(jí): 2 4 3
PID Arrival Burst Priority Completion Waiting Turnaround
1 0 5 2 8 3 8
2 1 3 1 4 0 3
3 2 4 3 12 6 10

說(shuō)明:本代碼優(yōu)先級(jí)數(shù)字越小,優(yōu)先級(jí)越高。

時(shí)間點(diǎn) 0:

  • 只有P1到達(dá),P1開(kāi)始執(zhí)行,因?yàn)樗俏ㄒ坏倪M(jìn)程。

時(shí)間點(diǎn) 1:

  • P2到達(dá),P2的優(yōu)先級(jí)(1)高于正在執(zhí)行的P1的優(yōu)先級(jí)(2)。
  • 根據(jù)搶占式調(diào)度規(guī)則,P2立即搶占P1,P1被掛起。
  • P2開(kāi)始執(zhí)行。

時(shí)間點(diǎn) 4:

  • P2完成執(zhí)行(它的執(zhí)行時(shí)間是3個(gè)單位,從時(shí)間點(diǎn)1到4)。
  • P1繼續(xù)執(zhí)行,因?yàn)榇藭r(shí)沒(méi)有優(yōu)先級(jí)更高的進(jìn)程。

時(shí)間點(diǎn) 2:

  • P3到達(dá),雖然它的優(yōu)先級(jí)(3)低于P1(2),但此時(shí)P1已經(jīng)被P2搶占,P3需要等待。
  • P1繼續(xù)執(zhí)行。

時(shí)間點(diǎn) 8:

  • P1完成執(zhí)行,P3開(kāi)始執(zhí)行。

時(shí)間點(diǎn) 12:

  • P3完成執(zhí)行。

6.4 輪轉(zhuǎn)調(diào)度(Round Robin, RR)

**輪轉(zhuǎn)調(diào)度(Round Robin, RR)**是一種時(shí)間片輪轉(zhuǎn)調(diào)度算法。每個(gè)進(jìn)程按照到達(dá)順序進(jìn)入隊(duì)列,并按照固定的時(shí)間片(time quantum)運(yùn)行。當(dāng)一個(gè)進(jìn)程的時(shí)間片用完時(shí),它被放到隊(duì)列的末尾,等待下一輪的調(diào)度。如果在時(shí)間片內(nèi)進(jìn)程未完成執(zhí)行,它將在下一輪繼續(xù)執(zhí)行。輪轉(zhuǎn)調(diào)度非常適合時(shí)間共享系統(tǒng),它在處理器上公平地分配CPU時(shí)間,使得每個(gè)進(jìn)程都有機(jī)會(huì)運(yùn)行。

#include <stdio.h>// 定義進(jìn)程結(jié)構(gòu)體
struct Process {int pid;            // 進(jìn)程IDint arrival_time;   // 到達(dá)時(shí)間int burst_time;     // 執(zhí)行時(shí)間int remaining_time; // 剩余執(zhí)行時(shí)間int completion_time;// 完成時(shí)間int waiting_time;   // 等待時(shí)間int turnaround_time;// 周轉(zhuǎn)時(shí)間
};// 輪轉(zhuǎn)調(diào)度算法的實(shí)現(xiàn)
void round_robin_scheduling(struct Process processes[], int n, int time_quantum) {int current_time = 0;  // 當(dāng)前時(shí)間int completed = 0;     // 已完成的進(jìn)程數(shù)int i = 0;             // 進(jìn)程索引// 循環(huán)直到所有進(jìn)程完成while (completed != n) {// 如果當(dāng)前進(jìn)程已到達(dá)且仍有剩余時(shí)間需要執(zhí)行if (processes[i].arrival_time <= current_time && processes[i].remaining_time > 0) {// 如果剩余時(shí)間大于時(shí)間片,則運(yùn)行時(shí)間片大小的時(shí)間if (processes[i].remaining_time > time_quantum) {current_time += time_quantum;                // 增加當(dāng)前時(shí)間processes[i].remaining_time -= time_quantum; // 減少剩余執(zhí)行時(shí)間} else {// 否則運(yùn)行剩余時(shí)間并完成進(jìn)程current_time += processes[i].remaining_time; // 增加當(dāng)前時(shí)間processes[i].remaining_time = 0;             // 設(shè)置剩余執(zhí)行時(shí)間為0processes[i].completion_time = current_time; // 更新完成時(shí)間// 計(jì)算周轉(zhuǎn)時(shí)間 = 完成時(shí)間 - 到達(dá)時(shí)間processes[i].turnaround_time = processes[i].completion_time - processes[i].arrival_time;// 計(jì)算等待時(shí)間 = 周轉(zhuǎn)時(shí)間 - 執(zhí)行時(shí)間processes[i].waiting_time = processes[i].turnaround_time - processes[i].burst_time;completed++; // 進(jìn)程已完成,增加已完成的進(jìn)程數(shù)}}// 循環(huán)遍歷下一個(gè)進(jìn)程i = (i + 1) % n;}
}// 打印所有進(jìn)程的信息,包括PID、到達(dá)時(shí)間、執(zhí)行時(shí)間、完成時(shí)間、等待時(shí)間和周轉(zhuǎn)時(shí)間
void print_processes(struct Process processes[], int n) {printf("PID\tArrival\tBurst\tCompletion\tWaiting\tTurnaround\n");for (int i = 0; i < n; i++) {printf("%d\t%d\t%d\t%d\t\t%d\t%d\n",processes[i].pid,processes[i].arrival_time,processes[i].burst_time,processes[i].completion_time,processes[i].waiting_time,processes[i].turnaround_time);}
}int main() {int n, time_quantum;// 用戶輸入進(jìn)程數(shù)量printf("輸入進(jìn)程數(shù)量: ");scanf("%d", &n);struct Process processes[n];// 用戶輸入每個(gè)進(jìn)程的到達(dá)時(shí)間和執(zhí)行時(shí)間for (int i = 0; i < n; i++) {printf("輸入進(jìn)程 %d 的到達(dá)時(shí)間和執(zhí)行時(shí)間: ", i + 1);scanf("%d %d", &processes[i].arrival_time, &processes[i].burst_time);processes[i].pid = i + 1;                            // 設(shè)置進(jìn)程IDprocesses[i].remaining_time = processes[i].burst_time; // 初始化剩余執(zhí)行時(shí)間為執(zhí)行時(shí)間}// 用戶輸入時(shí)間片大小printf("輸入時(shí)間片大小: ");scanf("%d", &time_quantum);// 調(diào)用輪轉(zhuǎn)調(diào)度算法round_robin_scheduling(processes, n, time_quantum);// 打印調(diào)度結(jié)果print_processes(processes, n);return 0;
}

運(yùn)行結(jié)果:

輸入進(jìn)程數(shù)量: 3
輸入進(jìn)程 1 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 0 5
輸入進(jìn)程 2 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 1 3
輸入進(jìn)程 3 的到達(dá)時(shí)間和執(zhí)行時(shí)間: 2 4
輸入時(shí)間片大小: 2
PID Arrival Burst Completion Waiting Turnaround
1 0 5 12 7 12
2 1 3 9 5 8
3 2 4 11 5 9

時(shí)間點(diǎn) 0-2

  • P1到達(dá)并執(zhí)行2個(gè)時(shí)間單位(時(shí)間片大小為2),剩余執(zhí)行時(shí)間為3。
  • 當(dāng)前時(shí)間為2。

時(shí)間點(diǎn) 2-4

  • P2到達(dá)(時(shí)間點(diǎn)1),開(kāi)始執(zhí)行2個(gè)時(shí)間單位,剩余執(zhí)行時(shí)間為1。
  • 當(dāng)前時(shí)間為4。

時(shí)間點(diǎn) 4-6

  • P3到達(dá)(時(shí)間點(diǎn)2),開(kāi)始執(zhí)行2個(gè)時(shí)間單位,剩余執(zhí)行時(shí)間為2。
  • 當(dāng)前時(shí)間為6。

時(shí)間點(diǎn) 6-8

  • P1輪到再次執(zhí)行,執(zhí)行2個(gè)時(shí)間單位,剩余1個(gè)時(shí)間單位。
  • 當(dāng)前時(shí)間為8。

時(shí)間點(diǎn) 8-9

  • P2輪到繼續(xù)執(zhí)行,執(zhí)行1個(gè)時(shí)間單位,完成任務(wù)。
  • 當(dāng)前時(shí)間為9。

時(shí)間點(diǎn) 9-10

  • P3繼續(xù)執(zhí)行,執(zhí)行1個(gè)時(shí)間單位,剩余1個(gè)時(shí)間單位。
  • 當(dāng)前時(shí)間為10。

時(shí)間點(diǎn) 10-11

  • P3最后執(zhí)行剩余的1個(gè)時(shí)間單位,完成任務(wù)。
  • 當(dāng)前時(shí)間為11。

時(shí)間點(diǎn) 11-12

  • P1最后執(zhí)行剩余的1個(gè)時(shí)間單位,完成任務(wù)。
  • 當(dāng)前時(shí)間為12。

6.5 設(shè)置進(jìn)程優(yōu)先級(jí)

設(shè)置進(jìn)程優(yōu)先級(jí)是指在操作系統(tǒng)中為每個(gè)進(jìn)程分配一個(gè)優(yōu)先級(jí)值,該值決定了進(jìn)程在調(diào)度過(guò)程中的優(yōu)先順序。優(yōu)先級(jí)越高的進(jìn)程通常會(huì)比優(yōu)先級(jí)低的進(jìn)程更早獲得CPU資源,這對(duì)于實(shí)時(shí)操作系統(tǒng)和任務(wù)管理至關(guān)重要。在Linux中,使用nice命令可以設(shè)置進(jìn)程的優(yōu)先級(jí)。nice值的范圍通常是從-20(最高優(yōu)先級(jí))到19(最低優(yōu)先級(jí)),默認(rèn)值為0

命令示例:

# 以更高優(yōu)先級(jí)啟動(dòng)程序
nice -n -10 ./my_program# 調(diào)整正在運(yùn)行的進(jìn)程優(yōu)先級(jí)
renice -n 5 -p 1234  # 將 PID 為 1234 的進(jìn)程優(yōu)先級(jí)降低# 查看
top

運(yùn)行結(jié)果:

第一個(gè)終端:

liber@liber-VMware-Virtual-Platform:/home/c$ nice -n 10 ./receiver

第二個(gè)終端:

top - 16:47:25 up 1 day, 22:26, 9 users, load average: 2.84, 2.60, 2.17
任務(wù): 355 total, 2 running, 353 sleeping, 0 stopped, 0 zombie
%Cpu(s): 13.0 us, 24.8 sy, 41.1 ni, 19.6 id, 0.0 wa, 0.0 hi, 1.4 si, 0.0 st
MiB Mem : 3868.2 total, 122.3 free, 2645.8 used, 1346.7 buff/cache
MiB Swap: 3868.0 total, 2832.5 free, 1035.5 used. 1222.5 avail Mem

進(jìn)程號(hào) USER PR NI VIRT RES SHR %CPU %MEM TIME+ COMMAND
2100616 liber 30 10 2680 1408 1408 R 77.9 0.0 0:46.70 receiver

說(shuō)明:top命令是一個(gè)動(dòng)態(tài)顯示當(dāng)前系統(tǒng)任務(wù)的命令,它可以顯示每個(gè)進(jìn)程的PR(優(yōu)先級(jí))和NI(nice值)。

第三個(gè)終端:

liber@liber-VMware-Virtual-Platform:~$ sudo renice -n 5 -p 2100616
[sudo] liber 的密碼:
2100616 (process ID) 舊優(yōu)先級(jí)為 10,新優(yōu)先級(jí)為 5

7. 進(jìn)程的內(nèi)存管理

7.1 地址空間

  • 物理地址:這是計(jì)算機(jī)內(nèi)存芯片上的實(shí)際地址,由內(nèi)存硬件直接使用。
  • 邏輯地址(虛擬地址):這是由CPU生成的地址,是相對(duì)與進(jìn)程獨(dú)立的虛擬地址空間的地址,通常通過(guò)地址轉(zhuǎn)換機(jī)制映射到物理地址。

7.2 內(nèi)存分配

  • 靜態(tài)分配:在程序編譯時(shí)為變量分配固定的內(nèi)存空間,無(wú)法在運(yùn)行時(shí)調(diào)整。
  • 動(dòng)態(tài)分配:在程序運(yùn)行時(shí),根據(jù)需要分配和釋放內(nèi)存,例如使用堆(heap)和棧(stack)進(jìn)行管理。

7.3 常見(jiàn)的機(jī)制

機(jī)制描述
分段內(nèi)存被劃分為不同的段,每個(gè)段可以包含不同類型的數(shù)據(jù),如代碼段、數(shù)據(jù)段、棧段等。每個(gè)段有自己的基址和長(zhǎng)度。分段使得程序員可以將邏輯相關(guān)的內(nèi)存部分分開(kāi)處理,有助于保護(hù)和共享內(nèi)存。
分頁(yè)內(nèi)存被劃分為固定大小的頁(yè)(通常是4KB)。虛擬內(nèi)存的每一頁(yè)可以映射到物理內(nèi)存的任意一頁(yè)。分頁(yè)減少了內(nèi)存碎片的產(chǎn)生,使內(nèi)存管理更加高效。
虛擬內(nèi)存虛擬內(nèi)存是一種內(nèi)存管理技術(shù),它允許操作系統(tǒng)使用磁盤空間來(lái)擴(kuò)展物理內(nèi)存的容量。通過(guò)將不常用的頁(yè)面交換到磁盤,虛擬內(nèi)存讓系統(tǒng)能夠運(yùn)行超出實(shí)際物理內(nèi)存容量的程序。
頁(yè)面置換算法當(dāng)物理內(nèi)存滿了,需要將某些頁(yè)面換出到磁盤,這時(shí)會(huì)使用頁(yè)面置換算法。

7.4 頁(yè)面置換算法

7.4.1 FIFO(First-In, First-Out)頁(yè)面置換算法

FIFO頁(yè)面置換算法基于“先來(lái)先服務(wù)”的原則。它將最早進(jìn)入內(nèi)存的頁(yè)面作為最先被置換的候選者,不考慮頁(yè)面的使用頻率或最近使用時(shí)間。當(dāng)需要置換頁(yè)面時(shí),系統(tǒng)會(huì)選擇最早進(jìn)入內(nèi)存的頁(yè)面,將其換出,然后將新頁(yè)面加載到該位置。使用隊(duì)列(Queue)來(lái)跟蹤頁(yè)面的順序。隊(duì)列的頭部是最早進(jìn)入的頁(yè)面,尾部是最新進(jìn)入的頁(yè)面。當(dāng)新頁(yè)面進(jìn)入時(shí),移除隊(duì)列頭部的頁(yè)面,將新頁(yè)面添加到尾部。

簡(jiǎn)單案例:

#include <stdio.h>#define MAX_FRAMES 3 // 最大頁(yè)框數(shù)void fifo_page_replacement(int pages[], int n) {int frames[MAX_FRAMES] = {-1, -1, -1}; // 初始化頁(yè)框?yàn)榭?#xff0c;-1 表示空閑int current = 0; // 當(dāng)前頁(yè)框的索引int page_faults = 0; // 記錄頁(yè)面錯(cuò)誤次數(shù)printf("FIFO Page Replacement\n");printf("Page\tFrames\n");for (int i = 0; i < n; i++) {int page = pages[i];int found = 0;// 檢查頁(yè)面是否已經(jīng)在頁(yè)框中for (int j = 0; j < MAX_FRAMES; j++) {if (frames[j] == page) {found = 1; // 頁(yè)面已在內(nèi)存中,不需要替換break;}}if (!found) {// 如果頁(yè)面不在內(nèi)存中,替換最早進(jìn)入的頁(yè)面frames[current] = page; // 替換當(dāng)前頁(yè)框中的頁(yè)面current = (current + 1) % MAX_FRAMES; // 更新索引,確保循環(huán)替換page_faults++;// 打印當(dāng)前頁(yè)框的內(nèi)容printf("%d\t", page);for (int j = 0; j < MAX_FRAMES; j++) {if (frames[j] != -1) {printf("%d ", frames[j]); // 打印頁(yè)框中的頁(yè)面} else {printf("- "); // 打印空閑頁(yè)框}}printf("\n");}}printf("Total Page Faults: %d\n", page_faults); // 打印總的頁(yè)面錯(cuò)誤次數(shù)
}int main() {int n;// 輸入頁(yè)面序列長(zhǎng)度printf("輸入頁(yè)面序列長(zhǎng)度: ");scanf("%d", &n);int pages[n];// 輸入頁(yè)面序列printf("輸入頁(yè)面序列(以空格分隔): ");for (int i = 0; i < n; i++) {scanf("%d", &pages[i]);}fifo_page_replacement(pages, n);return 0;
}

運(yùn)行結(jié)果:

輸入頁(yè)面序列長(zhǎng)度: 6
輸入頁(yè)面序列(以空格分隔): 1 3 0 5 6 3
FIFO Page Replacement
Page Frames
1 1 - -
3 1 3 -
0 1 3 0
5 5 3 0
6 5 6 0
3 5 6 3
Total Page Faults: 6

解釋:

  • 頁(yè)面1加載到內(nèi)存,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):1 - -。

  • 頁(yè)面3加載到內(nèi)存,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):1 3 -。

  • 頁(yè)面0加載到內(nèi)存,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):1 3 0

  • 頁(yè)面5加載到內(nèi)存,替換1(最早進(jìn)入),產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):5 3 0。

  • 頁(yè)面6加載到內(nèi)存,替換3(最早進(jìn)入),產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):5 6 0。

  • 頁(yè)面3加載到內(nèi)存,替換0,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):5 6 3。

7.4.2 LRU(Least Recently Used)頁(yè)面置換算法

LRU頁(yè)面置換算法基于“最近最少使用”原則,選擇最久未被訪問(wèn)的頁(yè)面進(jìn)行置換。系統(tǒng)需要記錄每個(gè)頁(yè)面的最后一次訪問(wèn)時(shí)間或訪問(wèn)順序。當(dāng)需要置換頁(yè)面時(shí),選擇記錄中訪問(wèn)時(shí)間最久遠(yuǎn)的頁(yè)面進(jìn)行置換。

簡(jiǎn)單案例:

#include <stdio.h>#define MAX_FRAMES 3 // 最大頁(yè)框數(shù)void lru_page_replacement(int pages[], int n) {int frames[MAX_FRAMES] = {-1, -1, -1}; // 初始化頁(yè)框?yàn)榭?#xff0c;-1 表示空閑int counter[MAX_FRAMES] = {0}; // 記錄每個(gè)幀的使用時(shí)間int page_faults = 0;int time = 0; // 用于記錄當(dāng)前的時(shí)間printf("LRU Page Replacement\n");printf("Page\tFrames\n");for (int i = 0; i < n; i++) {int page = pages[i];int found = 0;// 檢查頁(yè)面是否已經(jīng)在頁(yè)框中for (int j = 0; j < MAX_FRAMES; j++) {if (frames[j] == page) {found = 1; // 頁(yè)面已在內(nèi)存中,不需要替換counter[j] = ++time; // 更新此頁(yè)面的使用時(shí)間break;}}if (!found) {// 查找最近最少使用的幀int lru_index = 0;for (int j = 1; j < MAX_FRAMES; j++) {if (counter[j] < counter[lru_index]) {lru_index = j; // 選擇最近最少使用的頁(yè)面進(jìn)行替換}}// 替換最久未使用的頁(yè)面frames[lru_index] = page;counter[lru_index] = ++time; // 更新使用時(shí)間page_faults++;// 打印當(dāng)前頁(yè)框的內(nèi)容printf("%d\t", page);for (int j = 0; j < MAX_FRAMES; j++) {if (frames[j] != -1) {printf("%d ", frames[j]); // 打印頁(yè)框中的頁(yè)面} else {printf("- "); // 打印空閑頁(yè)框}}printf("\n");}}printf("Total Page Faults: %d\n", page_faults); // 打印總的頁(yè)面錯(cuò)誤次數(shù)
}int main() {int n;// 輸入頁(yè)面序列長(zhǎng)度printf("輸入頁(yè)面序列長(zhǎng)度: ");scanf("%d", &n);int pages[n];// 輸入頁(yè)面序列printf("輸入頁(yè)面序列(以空格分隔): ");for (int i = 0; i < n; i++) {scanf("%d", &pages[i]);}// 調(diào)用LRU頁(yè)面置換算法lru_page_replacement(pages, n);return 0;
}

運(yùn)行結(jié)果:

輸入頁(yè)面序列長(zhǎng)度: 6
輸入頁(yè)面序列(以空格分隔): 1 3 0 3 5 6
LRU Page Replacement
Page Frames
1 1 - -
3 1 3 -
0 1 3 0
5 5 3 0
6 5 3 6
Total Page Faults: 5

解釋:

  • 頁(yè)面1加載到內(nèi)存,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):1 - -

  • 頁(yè)面3加載到內(nèi)存,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):1 3 -。

  • 頁(yè)面0加載到內(nèi)存,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):1 3 0。

  • 頁(yè)面3已經(jīng)在內(nèi)存中,更新其使用時(shí)間,無(wú)需替換,不產(chǎn)生頁(yè)面錯(cuò)誤。

  • 頁(yè)面5加載到內(nèi)存,替換最近最少使用的頁(yè)面1,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):5 3 0。

  • 頁(yè)面6加載到內(nèi)存,替換最近最少使用的頁(yè)面0,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):5 3 6。

7.4.3 LFU(Least Frequently Used)頁(yè)面置換算法

LFU頁(yè)面置換算法基于“最少使用頻率”原則,選擇在一段時(shí)間內(nèi)使用次數(shù)最少的頁(yè)面進(jìn)行置換。為每個(gè)頁(yè)面維護(hù)一個(gè)計(jì)數(shù)器,每次訪問(wèn)該頁(yè)面時(shí),計(jì)數(shù)器加1。當(dāng)需要置換頁(yè)面時(shí),選擇計(jì)數(shù)器值最小的頁(yè)面。

簡(jiǎn)單案例:

#include <stdio.h>#define MAX_FRAMES 3 // 最大頁(yè)框數(shù)void lfu_page_replacement(int pages[], int n) {int frames[MAX_FRAMES] = {-1, -1, -1}; // 初始化頁(yè)框?yàn)榭?#xff0c;-1 表示空閑int frequency[MAX_FRAMES] = {0}; // 記錄每個(gè)幀的使用頻率int age[MAX_FRAMES] = {0}; // 記錄每個(gè)幀的使用順序,用于解決頻率相同時(shí)的選擇int page_faults = 0;int time = 0; // 用于記錄每次頁(yè)面訪問(wèn)的時(shí)間printf("LFU Page Replacement\n");printf("Page\tFrames\n");for (int i = 0; i < n; i++) {int page = pages[i];int found = 0;// 檢查頁(yè)面是否已經(jīng)在頁(yè)框中for (int j = 0; j < MAX_FRAMES; j++) {if (frames[j] == page) {found = 1; // 頁(yè)面已在內(nèi)存中frequency[j]++; // 增加使用頻率age[j] = ++time; // 更新此頁(yè)面的訪問(wèn)時(shí)間break;}}if (!found) {// 選擇使用頻率最低且最早進(jìn)入的頁(yè)面進(jìn)行替換int lfu_index = 0;for (int j = 1; j < MAX_FRAMES; j++) {// 比較頻率,頻率低的優(yōu)先if (frequency[j] < frequency[lfu_index]) {lfu_index = j;} // 如果頻率相同,選擇最早進(jìn)入的頁(yè)面else if (frequency[j] == frequency[lfu_index] && age[j] < age[lfu_index]) {lfu_index = j;}}// 替換使用頻率最低的頁(yè)面frames[lfu_index] = page;frequency[lfu_index] = 1; // 重置使用頻率age[lfu_index] = ++time; // 更新頁(yè)面進(jìn)入時(shí)間page_faults++;}// 無(wú)論頁(yè)面是否已經(jīng)在內(nèi)存中,都打印當(dāng)前頁(yè)框的內(nèi)容printf("%d\t", page);for (int j = 0; j < MAX_FRAMES; j++) {if (frames[j] != -1) {printf("%d ", frames[j]); // 打印頁(yè)框中的頁(yè)面} else {printf("- "); // 打印空閑頁(yè)框}}printf("\n");}printf("Total Page Faults: %d\n", page_faults); // 打印總的頁(yè)面錯(cuò)誤次數(shù)
}int main() {int n;// 輸入頁(yè)面序列長(zhǎng)度printf("輸入頁(yè)面序列長(zhǎng)度: ");scanf("%d", &n);int pages[n];// 輸入頁(yè)面序列printf("輸入頁(yè)面序列(以空格分隔): ");for (int i = 0; i < n; i++) {scanf("%d", &pages[i]);}// 調(diào)用 LFU 頁(yè)面置換算法lfu_page_replacement(pages, n);return 0;
}

運(yùn)行結(jié)果:

輸入頁(yè)面序列長(zhǎng)度: 8
輸入頁(yè)面序列(以空格分隔): 1 2 3 4 2 1 5 6
LFU Page Replacement
Page Frames
1 1 - -
2 1 2 -
3 1 2 3
4 4 2 3
2 4 2 3
1 4 2 1
5 5 2 1
6 5 2 6
Total Page Faults: 7

解釋:

  • 頁(yè)面1:加載到內(nèi)存,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):1 - -。

  • 頁(yè)面2:加載到內(nèi)存,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):1 2 -。

  • 頁(yè)面3:加載到內(nèi)存,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):1 2 3。

  • 頁(yè)面4:在頻率相同的情況下,應(yīng)該選擇最早的頁(yè)面1替換,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):4 2 3。

  • 頁(yè)面2:已在內(nèi)存中,增加其頻率,無(wú)需替換。

  • 頁(yè)面1:在頻率相同的情況下,應(yīng)該選擇最早的頁(yè)面3替換,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):4 2 1。

  • 頁(yè)面5:在頻率相同的情況下,應(yīng)該選擇最早的頁(yè)面4替換,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):5 2 1

  • 頁(yè)面6:在頻率相同的情況下,應(yīng)該選擇最早的頁(yè)面1替換,產(chǎn)生頁(yè)面錯(cuò)誤,內(nèi)存狀態(tài):5 2 6

7.5 內(nèi)存映射

內(nèi)存映射(Memory Mapping)是操作系統(tǒng)提供的一種機(jī)制,它允許將文件或其他對(duì)象(如設(shè)備內(nèi)存)直接映射到進(jìn)程的地址空間。通過(guò)內(nèi)存映射,進(jìn)程可以像訪問(wèn)普通內(nèi)存一樣訪問(wèn)文件中的數(shù)據(jù),而不需要使用傳統(tǒng)的I/O操作。

mmap() 是一種高效的內(nèi)存管理技術(shù),可以將文件或設(shè)備映射到進(jìn)程的地址空間,允許進(jìn)程通過(guò)內(nèi)存直接訪問(wèn)文件內(nèi)容。

簡(jiǎn)單案例:

#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>int main() {// 打開(kāi)要映射的文件int fd = open("example.txt", O_RDONLY);if (fd == -1) {perror("open");return 1;}// 獲取文件大小struct stat st;if (fstat(fd, &st) == -1) {perror("fstat");close(fd);return 1;}// 將文件內(nèi)容映射到內(nèi)存char *mapped = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);if (mapped == MAP_FAILED) {perror("mmap");close(fd)return 1;}// 關(guān)閉文件描述符close(fd);// 現(xiàn)在可以直接訪問(wèn)文件內(nèi)容printf("File content:\n%.*s\n", (int)st.st_size, mapped);// 解除內(nèi)存映射if (munmap(mapped, st.st_size) == -1) {perror("munmap");return 1;}return 0;
}

運(yùn)行結(jié)果:

前提準(zhǔn)備:創(chuàng)建example.txt,隨便輸入一些內(nèi)容,我輸入的是HI,Word!

File content:
HI,Word!

解釋

  • 使用 mmap 將文件內(nèi)容映射到進(jìn)程的地址空間。PROT_READ 表示映射區(qū)域是可讀的,MAP_PRIVATE 表示創(chuàng)建私有副本,修改映射內(nèi)容不會(huì)影響原文件。
  • 映射成功后,可以通過(guò)指針 mapped 直接訪問(wèn)文件內(nèi)容。
  • 在不需要時(shí),使用 munmap 解除內(nèi)存映射,釋放資源。

8. 進(jìn)程的同步與鎖機(jī)制

進(jìn)程同步 是指在多個(gè)進(jìn)程或線程并發(fā)執(zhí)行時(shí),控制它們的執(zhí)行順序或訪問(wèn)順序,以確保共享資源被正確使用。進(jìn)程同步的目標(biāo)是避免以下問(wèn)題:

  • 競(jìng)爭(zhēng)條件:多個(gè)進(jìn)程或線程同時(shí)訪問(wèn)或修改共享資源,可能導(dǎo)致數(shù)據(jù)不一致或不可預(yù)知的行為。
  • 死鎖:兩個(gè)或多個(gè)進(jìn)程或線程相互等待對(duì)方釋放資源,導(dǎo)致所有進(jìn)程或線程都無(wú)法繼續(xù)執(zhí)行。
  • 資源饑餓:某些進(jìn)程或線程長(zhǎng)期無(wú)法獲得資源,導(dǎo)致無(wú)法正常執(zhí)行。

鎖機(jī)制 是實(shí)現(xiàn)進(jìn)程同步的常用手段之一。鎖可以用來(lái)確保在某一時(shí)刻,只有一個(gè)進(jìn)程或線程能夠訪問(wèn)特定的共享資源

進(jìn)程同步與鎖機(jī)制的主要類型及其特點(diǎn):

機(jī)制類型描述操作適用場(chǎng)景
互斥鎖 (Mutex)確保同一時(shí)刻只有一個(gè)進(jìn)程或線程可以訪問(wèn)共享資源,避免數(shù)據(jù)競(jìng)爭(zhēng)。Lock:請(qǐng)求鎖,鎖被占用時(shí)阻塞。
Unlock:釋放鎖。
需要獨(dú)占訪問(wèn)資源的場(chǎng)景,如更新共享數(shù)據(jù)結(jié)構(gòu)。
讀寫鎖 (Read-Write Lock)允許多個(gè)讀者同時(shí)讀取,但寫者獨(dú)占訪問(wèn),適用于讀多寫少的情況。Read Lock:請(qǐng)求讀鎖,可并發(fā)。
Write Lock:請(qǐng)求寫鎖,獨(dú)占。
Unlock:釋放鎖。
讀多寫少的資源訪問(wèn),如緩存。
自旋鎖 (Spinlock)進(jìn)程或線程忙等待,持續(xù)檢查鎖狀態(tài),適用于鎖定時(shí)間很短的情況。Lock:忙等待獲取鎖。
Unlock:釋放鎖。
短時(shí)間鎖定的臨界區(qū),避免上下文切換的開(kāi)銷。
信號(hào)量 (Semaphore)用于限制同時(shí)訪問(wèn)共享資源的進(jìn)程或線程的數(shù)量,控制并發(fā)。P (Wait):請(qǐng)求減少信號(hào)量值,阻塞等待。
V (Signal):增加信號(hào)量值,可能喚醒等待進(jìn)程。
控制資源訪問(wèn)數(shù)量,如限制同時(shí)訪問(wèn)數(shù)據(jù)庫(kù)連接數(shù)。
條件變量 (Condition Variable)用于進(jìn)程或線程間的信號(hào)傳遞,等待某一條件發(fā)生時(shí)進(jìn)行同步。Wait:等待條件滿足。
Signal:條件滿足時(shí)發(fā)信號(hào)喚醒。
需要在特定條件下進(jìn)行線程或進(jìn)程間的同步,如生產(chǎn)者-消費(fèi)者模型。
屏障 (Barrier)使一組線程或進(jìn)程必須全部到達(dá)某個(gè)同步點(diǎn)后才能繼續(xù)執(zhí)行,常用于并行計(jì)算。Wait:等待所有線程或進(jìn)程到達(dá)屏障點(diǎn)。并行計(jì)算中各部分任務(wù)需要同步協(xié)調(diào)的場(chǎng)景,如階段性任務(wù)同步。

8.1 互斥鎖 (Mutex)

互斥鎖是用于防止多個(gè)線程或進(jìn)程同時(shí)訪問(wèn)共享資源的鎖機(jī)制?;コ怄i保證在任一時(shí)刻,只有一個(gè)線程可以持有鎖并訪問(wèn)受保護(hù)的共享資源。其他線程在嘗試獲取已被持有的互斥鎖時(shí),會(huì)被阻塞,直到鎖被釋放。

  • 鎖定(Lock):線程請(qǐng)求互斥鎖。如果鎖已經(jīng)被其他線程持有,請(qǐng)求線程會(huì)被阻塞,直到鎖可用。
  • 解鎖(Unlock):線程釋放互斥鎖,使得其他阻塞的線程可以繼續(xù)執(zhí)行。
#include <stdio.h>
#include <pthread.h>// 定義互斥鎖
pthread_mutex_t lock;void *thread_function(void *arg) {int id = *(int *)arg;// 嘗試獲取互斥鎖pthread_mutex_lock(&lock);// 進(jìn)入臨界區(qū),訪問(wèn)共享資源printf("Thread %d is executing\n", id);// 模擬臨界區(qū)操作for (int i = 0; i < 5; i++) {printf("Thread %d is in critical section %d\n", id, i+1);}// 釋放互斥鎖pthread_mutex_unlock(&lock);return NULL;
}int main() {pthread_t thread1, thread2;int id1 = 1, id2 = 2;// 初始化互斥鎖pthread_mutex_init(&lock, NULL);// 創(chuàng)建兩個(gè)線程pthread_create(&thread1, NULL, thread_function, &id1);pthread_create(&thread2, NULL, thread_function, &id2);// 等待兩個(gè)線程完成pthread_join(thread1, NULL);pthread_join(thread2, NULL);// 銷毀互斥鎖pthread_mutex_destroy(&lock);return 0;
}

運(yùn)行結(jié)果:

Thread 1 is executing
Thread 1 is in critical section 1
Thread 1 is in critical section 2
Thread 1 is in critical section 3
Thread 1 is in critical section 4
Thread 1 is in critical section 5
Thread 2 is executing
Thread 2 is in critical section 1
Thread 2 is in critical section 2
Thread 2 is in critical section 3
Thread 2 is in critical section 4
Thread 2 is in critical section 5

解釋:

  • pthread_mutex_init(&lock, NULL); 初始化互斥鎖。在使用互斥鎖前,必須先初始化它。

  • 每個(gè)線程在進(jìn)入臨界區(qū)前都會(huì)嘗試獲取互斥鎖。使用 pthread_mutex_lock(&lock); 來(lái)獲取鎖。如果鎖已經(jīng)被其他線程持有,當(dāng)前線程會(huì)被阻塞,直到鎖可用。

  • 進(jìn)入臨界區(qū)后,線程可以安全地訪問(wèn)共享資源,如打印消息或修改共享變量。

  • 完成臨界區(qū)操作后,使用 pthread_mutex_unlock(&lock); 釋放鎖,使得其他線程可以繼續(xù)執(zhí)行。

  • (線程同步)pthread_join(thread1, NULL);pthread_join(thread2, NULL); 用于等待兩個(gè)線程完成執(zhí)行,確保主線程在它們執(zhí)行完畢后才繼續(xù)。

  • pthread_mutex_destroy(&lock); 在程序結(jié)束時(shí)銷毀互斥鎖,釋放資源。

8.2 讀寫鎖 (Read-Write Lock)

讀寫鎖 (Read-Write Lock) 是一種允許多個(gè)線程同時(shí)讀取共享資源,但只允許一個(gè)線程寫入共享資源的鎖機(jī)制。讀寫鎖提供了更高的并發(fā)性,因?yàn)樗试S多線程并發(fā)讀取數(shù)據(jù),同時(shí)防止寫操作和其他讀寫操作的沖突。

  • 讀鎖(Read Lock):多個(gè)線程可以同時(shí)獲取讀鎖,允許并發(fā)讀取共享資源。
  • 寫鎖(Write Lock):獲取寫鎖時(shí),必須等待所有讀鎖和其他寫鎖被釋放,確保寫操作的獨(dú)占性。
  • 解鎖(Unlock):釋放讀鎖或?qū)戞i,允許其他等待的線程繼續(xù)執(zhí)行。
#include <stdio.h>
#include <pthread.h>// 定義讀寫鎖
pthread_rwlock_t rwlock;// 共享資源
int shared_resource = 0;void *reader(void *arg) {int id = *(int *)arg;// 獲取讀鎖pthread_rwlock_rdlock(&rwlock);// 讀取共享資源printf("Reader %d: Shared resource = %d\n", id, shared_resource);// 釋放讀鎖pthread_rwlock_unlock(&rwlock);return NULL;
}void *writer(void *arg) {int id = *(int *)arg;// 獲取寫鎖pthread_rwlock_wrlock(&rwlock);// 寫入共享資源shared_resource += 10;printf("Writer %d: Updated shared resource to %d\n", id, shared_resource);// 釋放寫鎖pthread_rwlock_unlock(&rwlock);return NULL;
}int main() {pthread_t threads[3];int ids[3] = {1, 2, 3};// 初始化讀寫鎖pthread_rwlock_init(&rwlock, NULL);// 創(chuàng)建兩個(gè)讀線程和一個(gè)寫線程pthread_create(&threads[0], NULL, reader, &ids[0]);pthread_create(&threads[1], NULL, writer, &ids[1]);pthread_create(&threads[2], NULL, reader, &ids[2]);// 等待所有線程完成for (int i = 0; i < 3; i++) {pthread_join(threads[i], NULL);}// 銷毀讀寫鎖pthread_rwlock_destroy(&rwlock);return 0;
}

運(yùn)行結(jié)果:

Reader 1: Shared resource = 0
Writer 2: Updated shared resource to 10
Reader 3: Shared resource = 10

解釋:

  • pthread_rwlock_init(&rwlock, NULL); 初始化讀寫鎖。在使用讀寫鎖前,必須先初始化它。

  • 每個(gè)讀線程在讀取共享資源前會(huì)獲取讀鎖。使用 pthread_rwlock_rdlock(&rwlock); 來(lái)獲取讀鎖。多個(gè)讀線程可以同時(shí)獲取讀鎖,允許并發(fā)讀取。

  • 讀取共享資源后,使用 pthread_rwlock_unlock(&rwlock); 釋放讀鎖。

  • 寫線程在修改共享資源前會(huì)獲取寫鎖。使用 pthread_rwlock_wrlock(&rwlock); 來(lái)獲取寫鎖。獲取寫鎖后,寫線程可以獨(dú)占訪問(wèn)共享資源。

  • 修改共享資源后,使用 pthread_rwlock_unlock(&rwlock); 釋放寫鎖,允許其他讀寫操作繼續(xù)執(zhí)行。

  • pthread_join(threads[i], NULL); 用于等待所有線程完成執(zhí)行,確保主線程在它們執(zhí)行完畢后才繼續(xù)。

  • pthread_rwlock_destroy(&rwlock); 在程序結(jié)束時(shí)銷毀讀寫鎖,釋放資源。

8.3 自旋鎖 (Spinlock)

自旋鎖 (Spinlock) 是一種忙等待的鎖機(jī)制。在等待獲取鎖時(shí),線程不會(huì)進(jìn)入睡眠狀態(tài),而是持續(xù)檢查鎖的狀態(tài),直到獲得鎖為止。由于自旋鎖不會(huì)導(dǎo)致線程上下文切換,因此適用于鎖定時(shí)間非常短的場(chǎng)景。

  • 鎖定(Lock):線程嘗試獲取自旋鎖。如果鎖已被占用,線程會(huì)在獲取鎖之前一直循環(huán)檢查鎖的狀態(tài)。
  • 解鎖(Unlock):線程釋放自旋鎖,允許其他等待的線程獲取鎖。
#include <stdio.h>
#include <pthread.h>// 定義自旋鎖
pthread_spinlock_t spinlock;// 共享資源
int shared_resource = 0;void *thread_function(void *arg) {int id = *(int *)arg;// 嘗試獲取自旋鎖pthread_spin_lock(&spinlock);// 進(jìn)入臨界區(qū),訪問(wèn)共享資源printf("Thread %d is executing\n", id);shared_resource += 10;printf("Thread %d updated shared resource to %d\n", id, shared_resource);// 釋放自旋鎖pthread_spin_unlock(&spinlock);return NULL;
}int main() {pthread_t thread1, thread2;int id1 = 1, id2 = 2;// 初始化自旋鎖pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE);// 創(chuàng)建兩個(gè)線程pthread_create(&thread1, NULL, thread_function, &id1);pthread_create(&thread2, NULL, thread_function, &id2);// 等待兩個(gè)線程完成pthread_join(thread1, NULL);pthread_join(thread2, NULL);// 銷毀自旋鎖pthread_spin_destroy(&spinlock);return 0;
}

運(yùn)行結(jié)果:

liber@liber-VMware-Virtual-Platform:/home/c$ ./receiver
Thread 2 is executing
Thread 2 updated shared resource to 10
Thread 1 is executing
Thread 1 updated shared resource to 20

解釋:

  • pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE); 初始化自旋鎖。在使用自旋鎖前,必須先初始化它。這里的 PTHREAD_PROCESS_PRIVATE 表示自旋鎖僅用于單個(gè)進(jìn)程內(nèi)的線程之間。

  • 每個(gè)線程在進(jìn)入臨界區(qū)前都會(huì)嘗試獲取自旋鎖。使用 pthread_spin_lock(&spinlock); 來(lái)獲取鎖。自旋鎖不會(huì)讓線程進(jìn)入睡眠,而是會(huì)忙等待直到鎖可用。

  • 進(jìn)入臨界區(qū)后,線程可以安全地訪問(wèn)共享資源,如增加共享變量的值。

  • 完成臨界區(qū)操作后,使用 pthread_spin_unlock(&spinlock); 釋放鎖,使得其他線程可以繼續(xù)執(zhí)行。

  • pthread_join(thread1, NULL);pthread_join(thread2, NULL); 用于等待兩個(gè)線程完成執(zhí)行,確保主線程在它們執(zhí)行完畢后才繼續(xù)。

  • pthread_spin_destroy(&spinlock); 在程序結(jié)束時(shí)銷毀自旋鎖,釋放資源。

8.4 信號(hào)量 (Semaphore)

信號(hào)量 (Semaphore) 是一種用于控制多個(gè)進(jìn)程或線程對(duì)共享資源進(jìn)行訪問(wèn)的同步機(jī)制。信號(hào)量包含一個(gè)計(jì)數(shù)器,用來(lái)表示當(dāng)前可用資源的數(shù)量。信號(hào)量可以用來(lái)解決資源的互斥訪問(wèn)問(wèn)題,特別是在需要限制訪問(wèn)資源的進(jìn)程或線程數(shù)量時(shí)。

  • P 操作 (Wait/Down):試圖將信號(hào)量的值減1,如果信號(hào)量的值為0,則進(jìn)程或線程會(huì)被阻塞,直到信號(hào)量的值大于0。
  • V 操作 (Signal/Up):將信號(hào)量的值加1,如果有等待的進(jìn)程或線程,則喚醒它們。
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>// 定義信號(hào)量
sem_t semaphore;// 共享資源
int shared_resource = 0;void *thread_function(void *arg) {int id = *(int *)arg;// 嘗試獲取信號(hào)量sem_wait(&semaphore); // P 操作,等待信號(hào)量// 進(jìn)入臨界區(qū),訪問(wèn)共享資源printf("Thread %d is executing\n", id);shared_resource += 10;printf("Thread %d updated shared resource to %d\n", id, shared_resource);// 釋放信號(hào)量sem_post(&semaphore); // V 操作,釋放信號(hào)量return NULL;
}int main() {pthread_t threads[3];int ids[3] = {1, 2, 3};// 初始化信號(hào)量,初始值為1,表示同一時(shí)刻只能有一個(gè)線程進(jìn)入臨界區(qū)sem_init(&semaphore, 0, 1);// 創(chuàng)建三個(gè)線程for (int i = 0; i < 3; i++) {pthread_create(&threads[i], NULL, thread_function, &ids[i]);}// 等待所有線程完成for (int i = 0; i < 3; i++) {pthread_join(threads[i], NULL);}// 銷毀信號(hào)量sem_destroy(&semaphore);return 0;
}

運(yùn)行結(jié)果(其中一個(gè)):

Thread 1 is executing
Thread 1 updated shared resource to 10
Thread 2 is executing
Thread 2 updated shared resource to 20
Thread 3 is executing
Thread 3 updated shared resource to 30

解釋:

  • sem_init(&semaphore, 0, 1); 初始化信號(hào)量。0表示信號(hào)量只在當(dāng)前進(jìn)程內(nèi)有效,1是信號(hào)量的初始值,表示同時(shí)只能有一個(gè)線程訪問(wèn)資源。

  • 每個(gè)線程在進(jìn)入臨界區(qū)前會(huì)執(zhí)行 sem_wait(&semaphore); 進(jìn)行 P 操作(Wait/Down)。如果信號(hào)量的值為正,則將其減1并進(jìn)入臨界區(qū)。如果信號(hào)量的值為0,線程將被阻塞,直到信號(hào)量的值大于0。

  • 在臨界區(qū)內(nèi),線程可以安全地訪問(wèn)和修改共享資源。

  • 完成操作后,使用 sem_post(&semaphore); 進(jìn)行 V 操作(Signal/Up),將信號(hào)量的值加1,允許其他被阻塞的線程繼續(xù)執(zhí)行。

  • pthread_join(threads[i], NULL); 用于等待所有線程完成執(zhí)行,確保主線程在它們執(zhí)行完畢后才繼續(xù)。

  • sem_destroy(&semaphore); 在程序結(jié)束時(shí)銷毀信號(hào)量,釋放資源。

8.5 條件變量 (Condition Variable)

條件變量 (Condition Variable) 是一種允許線程等待某個(gè)條件發(fā)生并在條件滿足時(shí)進(jìn)行通知的同步機(jī)制。條件變量通常與互斥鎖一起使用,以確保在檢查或修改共享數(shù)據(jù)時(shí)線程不會(huì)進(jìn)入競(jìng)爭(zhēng)條件。

  • 等待 (Wait):線程在條件變量上等待,等待期間會(huì)釋放與之關(guān)聯(lián)的互斥鎖,直到被喚醒。當(dāng)被喚醒時(shí),線程重新獲取互斥鎖并繼續(xù)執(zhí)行。
  • 通知 (Signal/Broadcast):喚醒等待條件變量的一個(gè)或所有線程。Signal 通知一個(gè)線程,Broadcast 通知所有等待線程。
#include <stdio.h>
#include <pthread.h>#define BUFFER_SIZE 5// 共享資源
int buffer[BUFFER_SIZE];
int count = 0;// 互斥鎖和條件變量
pthread_mutex_t mutex;
pthread_cond_t cond_producer;
pthread_cond_t cond_consumer;void *producer(void *arg) {for (int i = 0; i < 10; i++) {pthread_mutex_lock(&mutex);// 如果緩沖區(qū)滿,等待消費(fèi)者消費(fèi)while (count == BUFFER_SIZE) {pthread_cond_wait(&cond_producer, &mutex);}// 生產(chǎn)數(shù)據(jù)buffer[count] = i;printf("Produced: %d\n", buffer[count]);count++;// 通知消費(fèi)者pthread_cond_signal(&cond_consumer);pthread_mutex_unlock(&mutex);}return NULL;
}void *consumer(void *arg) {for (int i = 0; i < 10; i++) {pthread_mutex_lock(&mutex);// 如果緩沖區(qū)空,等待生產(chǎn)者生產(chǎn)while (count == 0) {pthread_cond_wait(&cond_consumer, &mutex);}// 消費(fèi)數(shù)據(jù)printf("Consumed: %d\n", buffer[0]);// 將緩沖區(qū)中的數(shù)據(jù)前移,保持順序for (int j = 0; j < count - 1; j++) {buffer[j] = buffer[j + 1];}count--;// 通知生產(chǎn)者pthread_cond_signal(&cond_producer);pthread_mutex_unlock(&mutex);}return NULL;
}int main() {pthread_t prod_thread, cons_thread;// 初始化互斥鎖和條件變量pthread_mutex_init(&mutex, NULL);pthread_cond_init(&cond_producer, NULL);pthread_cond_init(&cond_consumer, NULL);// 創(chuàng)建生產(chǎn)者和消費(fèi)者線程pthread_create(&prod_thread, NULL, producer, NULL);pthread_create(&cons_thread, NULL, consumer, NULL);// 等待線程完成pthread_join(prod_thread, NULL);pthread_join(cons_thread, NULL);// 銷毀互斥鎖和條件變量pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond_producer);pthread_cond_destroy(&cond_consumer);return 0;
}

運(yùn)行結(jié)果(其中一個(gè)):

Produced: 0
Produced: 1
Produced: 2
Produced: 3
Produced: 4
Consumed: 0
Consumed: 1
Consumed: 2
Consumed: 3
Consumed: 4
Produced: 5
Produced: 6
Produced: 7
Produced: 8
Produced: 9
Consumed: 5
Consumed: 6
Consumed: 7
Consumed: 8
Consumed: 9

解釋:

  • pthread_mutex_init(&mutex, NULL); 初始化互斥鎖。
  • pthread_cond_init(&cond_producer, NULL);pthread_cond_init(&cond_consumer, NULL); 初始化生產(chǎn)者和消費(fèi)者條件變量。

生產(chǎn)者線程操作

  • 生產(chǎn)者線程在向緩沖區(qū)添加數(shù)據(jù)之前,會(huì)先獲取互斥鎖 pthread_mutex_lock(&mutex);。
  • 如果緩沖區(qū)已滿,生產(chǎn)者線程會(huì)等待 pthread_cond_wait(&cond_producer, &mutex);,并釋放互斥鎖,直到消費(fèi)者線程喚醒它。
  • 添加數(shù)據(jù)后,生產(chǎn)者線程會(huì)通知消費(fèi)者線程 pthread_cond_signal(&cond_consumer);,并釋放互斥鎖 pthread_mutex_unlock(&mutex);。

消費(fèi)者線程操作

  • 消費(fèi)者線程在消費(fèi)數(shù)據(jù)之前,同樣會(huì)獲取互斥鎖。
  • 如果緩沖區(qū)為空,消費(fèi)者線程會(huì)等待 pthread_cond_wait(&cond_consumer, &mutex);,并釋放互斥鎖,直到生產(chǎn)者線程喚醒它。
  • 消費(fèi)數(shù)據(jù)后,消費(fèi)者線程會(huì)通知生產(chǎn)者線程 pthread_cond_signal(&cond_producer);,并釋放互斥鎖。

同步操作:

  • pthread_join(prod_thread, NULL);pthread_join(cons_thread, NULL); 用于等待兩個(gè)線程完成執(zhí)行。

  • 在程序結(jié)束時(shí),銷毀互斥鎖和條件變量以釋放資源。

8.6 屏障 (Barrier)

屏障 (Barrier) 是一種同步機(jī)制,它使得一組線程必須全部到達(dá)某個(gè)同步點(diǎn)后,才能繼續(xù)執(zhí)行。這通常用于并行計(jì)算中,當(dāng)各個(gè)線程都完成了各自的一部分任務(wù)后,再繼續(xù)執(zhí)行下一步操作。

  • 等待 (Wait):線程在屏障處等待,直到所有其他線程都到達(dá)屏障。只有當(dāng)所有線程都到達(dá)屏障時(shí),它們才能繼續(xù)執(zhí)行。
#include <stdio.h>
#include <pthread.h>// 定義屏障
pthread_barrier_t barrier;void *thread_function(void *arg) {int id = *(int *)arg;// 每個(gè)線程完成各自的計(jì)算任務(wù)printf("Thread %d is performing its task before the barrier\n", id);// 等待其他線程到達(dá)屏障pthread_barrier_wait(&barrier);// 所有線程都到達(dá)屏障后繼續(xù)執(zhí)行printf("Thread %d has crossed the barrier and is continuing\n", id);return NULL;
}int main() {pthread_t threads[4];int ids[4] = {1, 2, 3, 4};// 初始化屏障,計(jì)數(shù)為4(表示4個(gè)線程需要同步)pthread_barrier_init(&barrier, NULL, 4);// 創(chuàng)建4個(gè)線程for (int i = 0; i < 4; i++) {pthread_create(&threads[i], NULL, thread_function, &ids[i]);}// 等待所有線程完成for (int i = 0; i < 4; i++) {pthread_join(threads[i], NULL);}// 銷毀屏障pthread_barrier_destroy(&barrier);return 0;
}

運(yùn)行結(jié)果(其中一個(gè)):

Thread 1 is performing its task before the barrier
Thread 3 is performing its task before the barrier
Thread 2 is performing its task before the barrier
Thread 4 is performing its task before the barrier
Thread 4 has crossed the barrier and is continuing
Thread 1 has crossed the barrier and is continuing
Thread 2 has crossed the barrier and is continuing
Thread 3 has crossed the barrier and is continuing

解釋:

  • thread_barrier_init(&barrier, NULL, 4); 初始化屏障,并設(shè)置需要同步的線程數(shù)量為4。即所有4個(gè)線程都需要到達(dá)屏障后,才能繼續(xù)執(zhí)行。

  • 每個(gè)線程在執(zhí)行完各自的任務(wù)后,調(diào)用 pthread_barrier_wait(&barrier); 進(jìn)入屏障等待狀態(tài)。

  • 當(dāng)所有線程都到達(dá)屏障后,屏障會(huì)解除,所有線程將繼續(xù)執(zhí)行后續(xù)的任務(wù)。

  • pthread_join(threads[i], NULL); 用于等待所有線程完成執(zhí)行,確保主線程在它們執(zhí)行完畢后才繼續(xù)。

  • pthread_barrier_destroy(&barrier); 在程序結(jié)束時(shí)銷毀屏障,釋放資源。

9. GDB進(jìn)程調(diào)試

gdb 是 GNU Debugger,用于調(diào)試程序,包括設(shè)置斷點(diǎn)、單步執(zhí)行、查看變量、分析崩潰等。

# 編譯程序時(shí)添加調(diào)試信息
gcc -g my_program.c -o my_program #記得加-g# 啟動(dòng) gdb 調(diào)試
gdb ./my_program# 常用 gdb 命令
break main   # 設(shè)置斷點(diǎn)在 main 函數(shù)
run          # 開(kāi)始運(yùn)行程序
next         # 單步執(zhí)行
print var    # 打印變量值
bt           # 打印調(diào)用棧

簡(jiǎn)單案例(test.c):

#include <stdio.h>void fun() {int array[5];for (int i = 0; i <= 5; i++) {  // 錯(cuò)誤:i 應(yīng)該小于 5array[i] = i * 10;printf("array[%d] = %d\n", i, array[i]);}
}int main() {fun();return 0;
}

運(yùn)行結(jié)果:

liber@liber-VMware-Virtual-Platform:/home/c$ gcc -g test.c -o test
liber@liber-VMware-Virtual-Platform:/home/c$ gdb ./test

Type “apropos word” to search for commands related to “word”…
Reading symbols from ./test…
(gdb) break fun #設(shè)置斷點(diǎn)
Breakpoint 1 at 0x1175: file test.c, line 3.
(gdb) run #開(kāi)始運(yùn)行程序
Starting program: /home/c/test

Breakpoint 1, fun () at test.c:3
3 void fun() {
(gdb) next
5 for (int i = 0; i <= 5; i++) { // 錯(cuò)誤:i 應(yīng)該小于 5
(gdb) next
6 array[i] = i * 10;
(gdb) print i #打印變量i

(gdb) next
7 printf(“array[%d] = %d\n”, i, array[i]);
(gdb) next
array[5] = 50 #數(shù)組越界
5 for (int i = 0; i <= 5; i++) { // 錯(cuò)誤:i 應(yīng)該小于 5
(gdb) next #下一步直接返回
9 }
(gdb) next
main () at test.c:13
13 return 0; #程序結(jié)束
(gdb)

說(shuō)明:加粗字段是指令。

?

http://www.risenshineclean.com/news/29192.html

相關(guān)文章:

  • 基于PHP的家教網(wǎng)站開(kāi)發(fā)環(huán)境谷歌seo服務(wù)商
  • 用六類網(wǎng)站做電話可以嗎長(zhǎng)尾關(guān)鍵詞搜索網(wǎng)站
  • seo網(wǎng)站優(yōu)化推廣怎么做東莞seo優(yōu)化案例
  • 最新新聞熱點(diǎn)事件2024摘抄優(yōu)化大師好用嗎
  • 簡(jiǎn)單的網(wǎng)頁(yè)設(shè)計(jì)代碼記事本專業(yè)的網(wǎng)站優(yōu)化公司排名
  • 做網(wǎng)站口碑比較好的大公司百度聯(lián)系電話多少
  • 知果果網(wǎng)站誰(shuí)做的軟文編輯
  • 淘外網(wǎng)站怎么做網(wǎng)站怎么申請(qǐng)?jiān)趺醋?cè)
  • 個(gè)人做購(gòu)物網(wǎng)站犯法嗎交換鏈接平臺(tái)
  • 做網(wǎng)站用小公司還是大公司2022最火營(yíng)銷方案
  • 2_網(wǎng)站建設(shè)的一般步驟包含哪些刷seo快速排名
  • 有沒(méi)有專門做av字幕的網(wǎng)站百度法務(wù)部聯(lián)系方式
  • 做網(wǎng)站具體指什么百度招商客服電話
  • 隨州網(wǎng)站seo常州百度推廣代理
  • 網(wǎng)站模板jsp設(shè)計(jì)公司排名前十強(qiáng)
  • 廠家批發(fā)網(wǎng)站平臺(tái)傳播易廣告投放平臺(tái)
  • 企業(yè)建設(shè)網(wǎng)站的好處有哪些常用的營(yíng)銷方法和手段
  • 自己制作視頻的app泉州seo培訓(xùn)
  • 提供微網(wǎng)站建設(shè)購(gòu)物網(wǎng)站推廣方案
  • 物聯(lián)網(wǎng)手機(jī)app開(kāi)發(fā)軟件天津seo方案
  • 星際網(wǎng)絡(luò)泰安網(wǎng)絡(luò)公司網(wǎng)站頁(yè)面優(yōu)化方法
  • 臺(tái)州網(wǎng)站搜索優(yōu)化友情鏈接工具
  • 三亞制作網(wǎng)站軍事新聞?lì)^條最新消息
  • 北票網(wǎng)站建設(shè)黃金網(wǎng)站軟件免費(fèi)
  • 做娛樂(lè)性手機(jī)網(wǎng)站推廣資源網(wǎng)
  • 直播間 網(wǎng)站建設(shè)app關(guān)鍵詞推廣
  • 淘寶客如何做網(wǎng)站今日新聞?lì)^條新聞
  • 聚財(cái)三個(gè)字公司名字哪個(gè)網(wǎng)站學(xué)seo是免費(fèi)的
  • 新網(wǎng)站快速提高排名互換鏈接的方法
  • 如何做網(wǎng)站對(duì)比網(wǎng)站優(yōu)化排名網(wǎng)站