目錄
例子1? ??獲取當前進程的進程標識符
例子2? ?創建一個新的子進程
例子3? ??展示了父進程和子進程的進程標識符
例子4? ? ?區分父進程和子進程
例子5? ? ?區分父進程和子進程的行為
例子6? ??比較進程標識符來區分父進程和子進程
例子7? ? ?子進程如何修改一個變量,對父進程的影響
例子8? ? ?子進程創建并循環執行,每隔3秒打印一條消息
例子9? ??父進程和子進程分別進入循環,每隔一秒打印一條消息
例子10? ? ?vfork()創建子進程
例子11? ??vfork() 創建子進程,執行一定次數后會自行退出
例子12? ??
例子13? ??創建子進程,父子不同的操作。子在一定條件下會自行退出
例子14? ? 父等待子進程結束后繼續執行
例子15? ??wait() 父等待子結束,父打印子進程的退出狀態
例子16? ?waitpid替代 wait檢查子狀態,waitpid允許父進程進行非阻塞檢查或等待特定的子進程結束
例子17? ?子在一定條件下會自行退出,而父進程僅打印一次信息
例子18? ?execl執行一個新的程序。這個函數屬于 exec 系列函數,它們用于替換當前進程的映像
例子19? ??execl函數來執行 /bin/ls 命令,通常用于列出目錄內容。如果 execl() 調用成功,則不會返回;如果調用失敗,會返回 -1 并打印錯誤信息
例子20? ??execl函數來執行 /bin/ls 命令,配上 -l 選項來以長格式列出目錄內容。如果 execl() 調用成功,則會替換當前進程的映像并不返回;如果失敗,會返回 -1 并打印錯誤信息
例子21? ??execl()執行系統命令 /bin/date,該命令用于顯示當前系統日期和時間。如果 execl()調用成功,它會替換當前進程的映像為 /bin/date 并不返回;如果失敗,會返回 -1 并打印錯誤信息
例子22? ??execlp()執行系統命令 ps,該命令用于顯示當前系統的進程狀態。如果 execlp() 調用成功,它會替換當前進程的映像為 ps 命令并不返回;如果失敗,會返回 -1 并打印錯誤信息
例子23? ??execvp()執行系統命令 ps,用于顯示當前系統的進程狀態。execvp() 類似于 execlp(),但允許通過一個參數數組來傳遞命令和其參數。如果 execvp() 調用成功,它會替換當前進程的映像為 ps 命令并不返回;如果失敗,會返回 -1 并打印錯誤信息
例子24? ??execv()執行 /bin/ps 命令,該命令用于顯示當前系統的進程狀態。execv() 類似于 execl(),但使用數組來傳遞命令和其參數。如果 execv() 調用成功,它會替換當前進程的映像為 /bin/ps 并不返回;如果失敗,會返回 -1 并打印錯誤信息
例子25? 輸入來觸發文件操作,在子進程中進行。這個例子特別是在輸入為 1 時,程序會修改配置文件 config.txt 中的一個特定值
例子26? ??根據輸入決定是否創建一個子進程來執行特定的程序 (changData),該程序預期對 config.txt 文件進行修改。如果輸入不是 1,則打印消息并繼續等待
例子27? ? 根據輸入決定執行一個外部命令(changData),該命令與配置文件 config.txt 相關聯。如果用戶輸入 1,程序會創建一個子進程,該子進程通過 system 函數調用外部程序 ./changData 來處理文件 config.txt
例子28? ??system() 執行系統命令(在本例中是 ps),這個命令用來列出當前運行的進程。然而,該代碼示例存在一個問題:它沒有捕獲 system() 調用的輸出
例子29? ?popen() 和 fread() 函數從 ps 命令獲取輸出并將其讀入到一個字符數組中。該程序展示了如何執行系統命令并捕獲其輸出,適合需要從命令行工具中直接讀取數據的場景
例子30? ?處理命令行參數。它通過遍歷 argc 和 argv 數組來打印所有傳遞給程序的參數
例子31? ?等待用戶輸入。當用戶輸入 1 時,程序會創建一個子進程,這個子進程會修改一個文件(./file1)中特定字符串("LENG=")之后的字符
例子32? ??execl()函數是為了替換當前的進程映像為/bin/ls命令的進程映像
例子33? ?vfork()創建子進程并控制執行順序
例子1? ??獲取當前進程的進程標識符
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid()int main()
{pid_t pid; // 定義進程標識符變量pid = getpid(); // 調用getpid()函數獲取當前進程的PIDprintf("my pid is %d\n", pid); // 打印當前進程的PIDwhile(1); // 使程序進入無限循環,防止程序立即結束return 0; // 正常情況下,程序不會執行到這里,因為上面有無限循環
}
例子2? ?創建一個新的子進程
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid() 和 fork()int main()
{pid_t pid; // 定義進程標識符變量pid = getpid(); // 調用getpid()函數獲取當前進程的PIDfork(); // 調用fork()創建一個子進程。父進程中,fork返回新創建的子進程的PID;在子進程中,fork返回0。printf("my pid is %d\n", pid); // 打印當前進程的PID,注意這里將在父進程和子進程中都執行。return 0; // 結束程序,父進程和子進程都會到達這里并退出
}
例子3? ??展示了父進程和子進程的進程標識符
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid() 和 fork()int main()
{pid_t pid; // 定義進程標識符變量pid = getpid(); // 調用getpid()函數獲取當前進程的PIDfork(); // 調用fork()創建一個子進程。父進程中,fork返回新創建的子進程的PID;在子進程中,fork返回0。// 在printf中顯示初始進程的PID和當前進程的PID。// "pid" 是調用fork()之前的父進程的PID。// "getpid()" 將獲取當前進程的PID,這在父進程和子進程中可能不同。printf("my pid is %d, current pro id:%d\n", pid, getpid());return 0; // 結束程序,父進程和子進程都會到達這里并退出
}
例子4? ? ?區分父進程和子進程
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid() 和 fork()int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲原始進程的PIDpid_t pid2; // 定義另一個pid_t類型變量來存儲fork后的進程PIDpid = getpid(); // 獲取并存儲當前進程的PIDprintf("before fork: pid = %d\n", pid); // 打印fork前的PIDfork(); // 創建一個新的子進程。父進程中,fork返回子進程的PID;子進程中,fork返回0。pid2 = getpid(); // 獲取fork后當前進程的PIDprintf("after fork: pid = %d\n", pid2); // 打印fork后的PIDif(pid == pid2){// 如果fork前后的PID相同,說明代碼在父進程中執行printf("this is father print\n");}else{// 如果fork前后的PID不同,說明代碼在子進程中執行printf("this is child print, child pid = %d\n", getpid());}return 0; // 程序結束,父子進程都將執行到此處并退出
}
例子5? ? ?區分父進程和子進程的行為
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid() 和 fork()int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲fork()的返回值// 打印當前進程的PID,此時為父進程printf("father: id=%d\n", getpid());pid = fork(); // 調用fork()來創建一個新的子進程if (pid > 0){// 如果pid大于0,說明是父進程執行的代碼塊// 在父進程中,fork()返回創建的子進程的PIDprintf("this is father print, pid = %d\n", getpid());}else if (pid == 0){// 如果pid等于0,說明是子進程執行的代碼塊// 在子進程中,fork()返回0printf("this is child print, child pid = %d\n", getpid());}// 兩個進程都將執行到這里,并結束程序return 0;
}
例子6? ??比較進程標識符來區分父進程和子進程
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid() 和 fork()int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲原始進程的PIDpid_t pid2; // 定義另一個pid_t類型變量來存儲fork后的進程PIDpid_t retpid; // 定義一個pid_t類型變量來存儲fork()的返回值pid = getpid(); // 獲取并存儲當前進程的PIDprintf("before fork: pid = %d\n", pid); // 打印fork前的PIDretpid = fork(); // 創建一個新的子進程。父進程中,fork返回子進程的PID;在子進程中,fork返回0。pid2 = getpid(); // 獲取fork后當前進程的PIDprintf("after fork: pid = %d\n", pid2); // 打印fork后的PIDif(pid == pid2){// 如果fork前后的PID相同,說明代碼在父進程中執行// retpid將是子進程的PID,因為在父進程中,fork()返回子進程的PIDprintf("this is father print: iretpid = %d\n", retpid);}else{// 如果fork前后的PID不同,說明代碼在子進程中執行// 在子進程中,fork()返回0printf("this is child print, retpid=%d, child pid = %d\n", retpid, getpid());}return 0; // 程序結束,父子進程都將執行到此處并退出
}
例子7? ? ?子進程如何修改一個變量,對父進程的影響
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid() 和 fork()int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲fork()的返回值int data = 10; // 定義一個整型變量data,并初始化為10// 打印當前進程的PID,此時為父進程printf("father: id=%d\n", getpid());pid = fork(); // 調用fork()來創建一個新的子進程if (pid > 0){// 如果pid大于0,說明是父進程執行的代碼塊// 在父進程中,fork()返回創建的子進程的PIDprintf("this is father print, pid = %d\n", getpid());}else if (pid == 0){// 如果pid等于0,說明是子進程執行的代碼塊// 在子進程中,fork()返回0printf("this is child print, child pid = %d\n", getpid());// 子進程中修改data變量data = data + 100; // 將data加100}// 在父進程和子進程中都將執行到這里,并打印data的值printf("data=%d\n", data);return 0; // 程序結束,父子進程都將執行到此處并退出
}
例子8? ? ?子進程創建并循環執行,每隔3秒打印一條消息
#include <stdio.h> // 引入標準輸入輸出庫,用于打印和輸入
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid(), fork() 和 sleep()int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲fork()的返回值int data = 10; // 定義一個整型變量data,并初始化為10while(1) { // 無限循環printf("please input a data\n"); // 提示用戶輸入數據scanf("%d", &data); // 從標準輸入讀取一個整數到變量dataif(data == 1) { // 如果輸入的數據是1pid = fork(); // 調用fork()來創建一個新的子進程if(pid > 0) {// 如果pid大于0,說明是父進程執行的代碼塊// 父進程不進行任何操作,繼續循環等待新的輸入}else if(pid == 0) {// 如果pid等于0,說明是子進程執行的代碼塊// 在子進程中,fork()返回0while(1) {// 子進程進入另一個無限循環,每隔3秒打印一次消息printf("do net request, pid=%d\n", getpid()); // 打印當前子進程的PIDsleep(3); // 使子進程休眠3秒}}}else {// 如果輸入的數據不是1printf("wait, do nothing\n"); // 打印等待信息}}return 0; // 程序理論上不會到達這里,因為有無限循環
}
例子9? ??父進程和子進程分別進入循環,每隔一秒打印一條消息
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid(), fork() 和 sleep()int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲fork()的返回值pid = fork(); // 調用fork()來創建一個新的子進程if (pid > 0){// 如果pid大于0,說明是父進程執行的代碼塊// 父進程進入一個無限循環while (1) {printf("this is father print, pid = %d\n", getpid()); // 打印父進程的信息和PIDsleep(1); // 父進程休眠1秒,減緩循環速度,防止過快消耗系統資源} }else if (pid == 0) {// 如果pid等于0,說明是子進程執行的代碼塊// 子進程進入一個無限循環while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子進程的信息和PIDsleep(1); // 子進程休眠1秒,同樣為了減緩循環速度} }return 0; // 程序理論上不會到達這里,因為父子進程都被設置在無限循環中
}
例子10? ? ?vfork()創建子進程
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid(), vfork() 和 sleep()int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲vfork()的返回值pid = vfork(); // 調用vfork()來創建一個新的子進程if (pid > 0){// 如果pid大于0,說明是父進程執行的代碼塊// 父進程進入一個無限循環while (1) {printf("this is father print, pid = %d\n", getpid()); // 打印父進程的信息和PIDsleep(1); // 父進程休眠1秒,減緩循環速度,防止過快消耗系統資源} }else if (pid == 0) {// 如果pid等于0,說明是子進程執行的代碼塊// 子進程進入一個無限循環while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子進程的信息和PIDsleep(1); // 子進程休眠1秒,同樣為了減緩循環速度} }return 0; // 程序理論上不會到達這里,因為父子進程都被設置在無限循環中
}
例子11? ??vfork() 創建子進程,執行一定次數后會自行退出
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid(), vfork() 和 sleep()
#include <stdlib.h> // 引入標準庫,用于 exit()int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲vfork()的返回值int cnt = 0; // 定義并初始化計數器pid = vfork(); // 調用vfork()來創建一個新的子進程if (pid > 0){// 如果pid大于0,說明是父進程執行的代碼塊// 父進程進入一個無限循環while (1) {printf("cnt=%d\n", cnt); // 打印父進程中的計數器值printf("this is father print, pid = %d\n", getpid()); // 打印父進程的信息和PIDsleep(1); // 父進程休眠1秒,減緩循環速度} }else if (pid == 0) {// 如果pid等于0,說明是子進程執行的代碼塊// 子進程進入一個無限循環while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子進程的信息和PIDsleep(1); // 子進程休眠1秒cnt++; // 子進程中的計數器增加if (cnt == 3) {exit(0); // 當計數器達到3時,子進程退出break; // 退出循環}} }return 0; // 程序理論上不會到達這里,因為父子進程都被設置在無限循環中
}
例子12? ??
例子13? ??創建子進程,父子不同的操作。子在一定條件下會自行退出
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid(), fork() 和 sleep()
#include <stdlib.h> // 引入標準庫,用于 exit()int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲fork()的返回值int cnt = 0; // 定義并初始化計數器pid = fork(); // 調用fork()來創建一個新的子進程if (pid > 0){// 如果pid大于0,說明是父進程執行的代碼塊// 父進程進入一個無限循環while (1) {printf("cnt=%d\n", cnt); // 打印父進程中的計數器值printf("this is father print, pid = %d\n", getpid()); // 打印父進程的信息和PIDsleep(1); // 父進程休眠1秒,減緩循環速度} }else if (pid == 0) {// 如果pid等于0,說明是子進程執行的代碼塊// 子進程進入一個無限循環while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子進程的信息和PIDsleep(1); // 子進程休眠1秒cnt++; // 子進程中的計數器增加if (cnt == 5) {exit(0); // 當計數器達到5時,子進程退出}} }return 0; // 程序理論上不會到達這里,因為父子進程都被設置在無限循環中
}
例子14? ? 父等待子進程結束后繼續執行
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid(), fork() 和 sleep()
#include <stdlib.h> // 引入標準庫,用于 exit()
#include <sys/wait.h> // 引入 wait() 函數需要的庫int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲fork()的返回值int cnt = 0; // 定義并初始化計數器pid = fork(); // 調用fork()來創建一個新的子進程if (pid > 0){// 如果pid大于0,說明是父進程執行的代碼塊wait(NULL); // 父進程等待任何子進程結束,這里不關心子進程的退出狀態// 父進程在子進程結束后繼續執行while (1) {printf("cnt=%d\n", cnt); // 打印父進程中的計數器值printf("this is father print, pid = %d\n", getpid()); // 打印父進程的信息和PIDsleep(1); // 父進程休眠1秒,減緩循環速度} }else if (pid == 0) {// 如果pid等于0,說明是子進程執行的代碼塊// 子進程進入一個無限循環while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子進程的信息和PIDsleep(1); // 子進程休眠1秒cnt++; // 子進程中的計數器增加if (cnt == 5) {exit(0); // 當計數器達到5時,子進程退出}} }return 0; // 程序理論上不會到達這里,因為父子進程都被設置在無限循環中
}
例子15? ??wait() 父等待子結束,父打印子進程的退出狀態
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid(), fork() 和 sleep()
#include <stdlib.h> // 引入標準庫,用于 exit()
#include <sys/wait.h> // 引入 wait() 函數所需的庫int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲fork()的返回值int cnt = 0; // 定義并初始化計數器int status = 10; // 定義一個整數來存儲子進程的退出狀態pid = fork(); // 調用fork()來創建一個新的子進程if (pid > 0){// 如果pid大于0,說明是父進程執行的代碼塊wait(&status); // 父進程等待子進程結束,并通過status變量獲取子進程的退出狀態printf("child quit, child status = %d\n", WEXITSTATUS(status)); // 打印子進程的退出狀態// 父進程在子進程結束后繼續執行while (1) {printf("cnt=%d\n", cnt); // 打印父進程中的計數器值printf("this is father print, pid = %d\n", getpid()); // 打印父進程的信息和PIDsleep(1); // 父進程休眠1秒,減緩循環速度} }else if (pid == 0) {// 如果pid等于0,說明是子進程執行的代碼塊// 子進程進入一個無限循環while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子進程的信息和PIDsleep(1); // 子進程休眠1秒cnt++; // 子進程中的計數器增加if (cnt == 5) {exit(3); // 當計數器達到5時,子進程退出并返回狀態碼3}} }return 0; // 程序理論上不會到達這里,因為父子進程都被設置在無限循環中
}
例子16? ?waitpid替代 wait檢查子狀態,waitpid允許父進程進行非阻塞檢查或等待特定的子進程結束
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid(), fork() 和 sleep()
#include <stdlib.h> // 引入標準庫,用于 exit()
#include <sys/wait.h> // 引入等待函數庫,用于 waitpid()int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲fork()的返回值int cnt = 0; // 定義并初始化計數器int status = 10; // 定義一個整數來存儲子進程的退出狀態pid = fork(); // 調用fork()來創建一個新的子進程if (pid > 0){// 如果pid大于0,說明是父進程執行的代碼塊waitpid(pid, &status, WNOHANG); // 使用非阻塞方式等待子進程結束,不會掛起父進程printf("child quit, child status = %d\n", WEXITSTATUS(status)); // 打印子進程的退出狀態// 父進程在子進程結束后繼續執行while (1) {printf("cnt=%d\n", cnt); // 打印父進程中的計數器值printf("this is father print, pid = %d\n", getpid()); // 打印父進程的信息和PIDsleep(1); // 父進程休眠1秒,減緩循環速度} }else if (pid == 0) {// 如果pid等于0,說明是子進程執行的代碼塊// 子進程進入一個無限循環while (1) {printf("this is child print, pid = %d\n", getpid()); // 打印子進程的信息和PIDsleep(1); // 子進程休眠1秒cnt++; // 子進程中的計數器增加if (cnt == 5) {exit(3); // 當計數器達到5時,子進程退出并返回狀態碼3}} }return 0; // 程序理論上不會到達這里,因為父子進程都被設置在無限循環中
}
例子17? ?子在一定條件下會自行退出,而父進程僅打印一次信息
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <sys/types.h> // 引入數據類型,包括 pid_t
#include <unistd.h> // 引入 POSIX 操作系統API,包括 getpid(), getppid(), fork() 和 sleep()
#include <stdlib.h> // 引入標準庫,用于 exit()int main()
{pid_t pid; // 定義一個pid_t類型變量來存儲fork()的返回值int cnt = 0; // 定義并初始化計數器pid = fork(); // 調用fork()來創建一個新的子進程if (pid > 0){// 如果pid大于0,說明是父進程執行的代碼塊printf("this is father print, pid = %d\n", getpid()); // 打印父進程的信息和PID// 父進程沒有進入循環,將直接結束執行}else if (pid == 0) {// 如果pid等于0,說明是子進程執行的代碼塊// 子進程進入一個無限循環,直到cnt等于5while (1) {printf("this is child print, pid = %d, my father pid=%d\n", getpid(), getppid()); // 打印子進程的信息和其父進程的PIDsleep(1); // 子進程休眠1秒cnt++; // 子進程中的計數器增加if (cnt == 5) {exit(3); // 當計數器達到5時,子進程退出并返回狀態碼3}} }return 0; // 父進程執行完打印后將結束,子進程在計數達到5后也將結束
}
例子18? ?execl執行一個新的程序。這個函數屬于 exec 系列函數,它們用于替換當前進程的映像
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <stdlib.h> // 引入標準庫,用于標準庫功能
#include <unistd.h> // 引入 POSIX 操作系統API,包括 execl()// 函數原型:int execl(const char *path, const char *arg, ...);int main(void)
{// 打印 "before execl" 表明當前在調用 execl 前printf("before execl\n");// 調用 execl 執行名為 "echoarg" 的程序,該程序應在當前目錄下// "echoarg" 是被執行程序的名稱,同時也是傳遞給該程序的第一個參數// "abc" 是傳遞給 echoarg 程序的第二個參數// NULL 表示參數列表的結束if(execl("./echoarg", "echoarg", "abc", NULL) == -1){// 如果 execl 返回 -1,則表示執行失敗printf("execl failed!\n");// perror 用于打印上一個函數調用的錯誤描述(基于全局的 errno 變量)perror("why");}// 由于 execl 成功時不返回,如果程序執行到這里說明 execl 調用失敗printf("after execl\n");return 0;
}
例子19? ??execl函數來執行 /bin/ls 命令,通常用于列出目錄內容。如果 execl() 調用成功,則不會返回;如果調用失敗,會返回 -1 并打印錯誤信息
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <stdlib.h> // 引入標準庫,用于標準庫功能
#include <unistd.h> // 引入 POSIX 操作系統API,包括 execl()// 函數原型:int execl(const char *path, const char *arg, ...);int main(void)
{// 打印 "before execl" 表明當前在調用 execl 前printf("before execl\n");// 調用 execl 執行位于 "/bin/ls" 的程序,通常用于列出目錄內容// "ls" 是傳遞給 /bin/ls 程序的參數,用于識別程序名稱// NULL 指示參數列表的結束if(execl("/bin/ls", "ls", NULL, NULL) == -1){// 如果 execl 返回 -1,則表示執行失敗printf("execl failed!\n"); // perror 用于打印上一個函數調用的錯誤描述(基于全局的 errno 變量)perror("why");}// 由于 execl 成功時不返回,如果程序執行到這里說明 execl 調用失敗printf("after execl\n");return 0;
}
例子20? ??execl函數來執行 /bin/ls 命令,配上 -l 選項來以長格式列出目錄內容。如果 execl() 調用成功,則會替換當前進程的映像并不返回;如果失敗,會返回 -1 并打印錯誤信息
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <stdlib.h> // 引入標準庫,用于標準庫功能
#include <unistd.h> // 引入 POSIX 操作系統API,包括 execl()// 函數原型:int execl(const char *path, const char *arg, ...);int main(void)
{// 打印 "before execl" 表明當前在調用 execl 前printf("before execl\n");// 調用 execl 執行位于 "/bin/ls" 的程序,使用 "-l" 選項來以詳細列表格式列出文件和目錄// "ls" 是傳遞給 /bin/ls 程序的參數,用于識別程序名稱// "-l" 是一個參數,告訴 ls 命令以長格式顯示信息// NULL 指示參數列表的結束if(execl("/bin/ls", "ls", "-l", NULL) == -1){// 如果 execl 返回 -1,則表示執行失敗printf("execl failed!\n"); // perror 用于打印上一個函數調用的錯誤描述(基于全局的 errno 變量)perror("why");}// 由于 execl 成功時不返回,如果程序執行到這里說明 execl 調用失敗printf("after execl\n");return 0;
}
例子21? ??execl()執行系統命令 /bin/date,該命令用于顯示當前系統日期和時間。如果 execl()調用成功,它會替換當前進程的映像為 /bin/date 并不返回;如果失敗,會返回 -1 并打印錯誤信息
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <stdlib.h> // 引入標準庫,用于標準庫功能
#include <unistd.h> // 引入 POSIX 操作系統API,包括 execl()// 函數原型:int execl(const char *path, const char *arg, ...);int main(void)
{// 打印信息,表明程序意圖獲取當前系統日期printf("this pro get system date:\n");// 調用 execl 執行位于 "/bin/date" 的系統命令// "date" 是傳遞給 /bin/date 程序的參數,用于識別程序名稱// NULL 指示參數列表的結束if(execl("/bin/date", "date", NULL, NULL) == -1){// 如果 execl 返回 -1,則表示執行失敗printf("execl failed!\n"); // perror 用于打印上一個函數調用的錯誤描述(基于全局的 errno 變量)perror("why");}// 由于 execl 成功時不返回,如果程序執行到這里說明 execl 調用失敗printf("after execl\n");return 0;
}
例子22? ??execlp()執行系統命令 ps,該命令用于顯示當前系統的進程狀態。如果 execlp() 調用成功,它會替換當前進程的映像為 ps 命令并不返回;如果失敗,會返回 -1 并打印錯誤信息
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <stdlib.h> // 引入標準庫,用于標準庫功能
#include <unistd.h> // 引入 POSIX 操作系統API,包括 execlp()// 函數原型:int execl(const char *path, const char *arg, ...);int main(void)
{// 打印信息,表明程序意圖獲取當前系統進程狀態printf("this pro get system date:\n");// 調用 execlp 執行系統命令 "ps"// "ps" 是傳遞給 execlp() 的參數,用于執行 ps 命令顯示進程信息// NULL 指示參數列表的結束if(execlp("ps", "ps", NULL, NULL) == -1){// 如果 execlp 返回 -1,則表示執行失敗printf("execl failed!\n");// perror 用于打印上一個函數調用的錯誤描述(基于全局的 errno 變量)perror("why");}// 由于 execlp 成功時不返回,如果程序執行到這里說明 execlp 調用失敗printf("after execl\n");return 0;
}
例子23? ??execvp()執行系統命令 ps,用于顯示當前系統的進程狀態。execvp() 類似于 execlp(),但允許通過一個參數數組來傳遞命令和其參數。如果 execvp() 調用成功,它會替換當前進程的映像為 ps 命令并不返回;如果失敗,會返回 -1 并打印錯誤信息
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <stdlib.h> // 引入標準庫,用于標準庫功能
#include <unistd.h> // 引入 POSIX 操作系統API,包括 execvp()// 函數原型:int execvp(const char *file, char *const argv[]);int main(void)
{// 打印信息,表明程序意圖獲取當前系統進程狀態printf("this pro get system date:\n");// 創建參數數組,用于傳遞給 execvp()char *argv[] = {"ps", NULL, NULL};// 調用 execvp 執行系統命令 "ps"// "ps" 是傳遞給 execvp() 的命令,argv 是命令和參數的數組if(execvp("ps", argv) == -1){// 如果 execvp 返回 -1,則表示執行失敗printf("execl failed!\n"); // perror 用于打印上一個函數調用的錯誤描述(基于全局的 errno 變量)perror("why");}// 由于 execvp 成功時不返回,如果程序執行到這里說明 execvp 調用失敗printf("after execl\n");return 0;
}
例子24? ??execv()執行 /bin/ps 命令,該命令用于顯示當前系統的進程狀態。execv() 類似于 execl(),但使用數組來傳遞命令和其參數。如果 execv() 調用成功,它會替換當前進程的映像為 /bin/ps 并不返回;如果失敗,會返回 -1 并打印錯誤信息
#include <stdio.h> // 引入標準輸入輸出庫,用于打印
#include <stdlib.h> // 引入標準庫,用于標準庫功能
#include <unistd.h> // 引入 POSIX 操作系統API,包括 execv()// 函數原型:int execv(const char *path, char *const argv[]);int main(void)
{// 打印信息,表明程序意圖獲取當前系統進程狀態printf("this pro get system date:\n");// 創建參數數組,用于傳遞給 execv()char *argv[] = {"ps", NULL, NULL}; // "ps" 是命令名,NULL 表示參數列表結束// 調用 execv 執行位于 "/bin/ps" 的系統命令// "/bin/ps" 是命令的完整路徑// argv 是命令和參數的數組if(execv("/bin/ps", argv) == -1){// 如果 execv 返回 -1,則表示執行失敗printf("execl failed!\n");// perror 用于打印上一個函數調用的錯誤描述(基于全局的 errno 變量)perror("why");}// 由于 execv 成功時不返回,如果程序執行到這里說明 execv 調用失敗printf("after execl\n");return 0;
}
例子25? 輸入來觸發文件操作,在子進程中進行。這個例子特別是在輸入為 1 時,程序會修改配置文件 config.txt 中的一個特定值
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main()
{pid_t pid; // 用于存儲進程IDint data = 10; // 用戶輸入的數據初始化為10while(1) { // 無限循環,直到程序被外部方式終止printf("please input a data\n"); // 提示用戶輸入數據scanf("%d", &data); // 讀取用戶輸入的整數數據if(data == 1) { // 如果輸入的數據為1,則進行文件操作int fdSrc; // 文件描述符pid = fork(); // 創建子進程if(pid > 0) {wait(NULL); // 父進程等待子進程完成}if(pid == 0) { // 子進程代碼塊char *readBuf = NULL; // 讀緩沖區指針fdSrc = open("config.txt", O_RDWR); // 打開文件config.txt進行讀寫操作int size = lseek(fdSrc, 0, SEEK_END); // 獲取文件大小lseek(fdSrc, 0, SEEK_SET); // 將文件指針重置到文件開始readBuf = (char *)malloc(sizeof(char) * size + 8); // 分配讀緩沖區內存int n_read = read(fdSrc, readBuf, size); // 讀取文件內容到緩沖區char *p = strstr(readBuf, "LENG="); // 在緩沖區中查找"LENG="if(p == NULL) {printf("not found\n"); // 如果沒有找到,打印未找到并退出exit(-1);}p = p + strlen("LENG="); // 移動指針到"LENG="之后*p = '5'; // 修改內容lseek(fdSrc, 0, SEEK_SET); // 將文件指針重置到文件開始int n_write = write(fdSrc, readBuf, strlen(readBuf)); // 將修改后的緩沖區內容寫回文件close(fdSrc); // 關閉文件exit(0); // 子進程退出}} else {printf("wait, do nothing\n"); // 如果輸入不是1,提示等待}}return 0; // 主程序循環,實際上這里永遠不會執行到
}
例子26? ??根據輸入決定是否創建一個子進程來執行特定的程序 (changData),該程序預期對 config.txt 文件進行修改。如果輸入不是 1,則打印消息并繼續等待
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main()
{pid_t pid; // 用于存儲進程IDint data = 10; // 用戶輸入的數據初始化為10while(1) { // 無限循環,直到程序被外部方式終止printf("please input a data\n"); // 提示用戶輸入數據scanf("%d", &data); // 讀取用戶輸入的整數數據if(data == 1) { // 如果輸入的數據為1,則進行操作int fdSrc; // 文件描述符,雖然在此代碼版本中未被使用pid = fork(); // 創建子進程if(pid > 0) {wait(NULL); // 父進程等待子進程完成}if(pid == 0) { // 子進程代碼塊// 子進程執行一個外部程序 "changData"// 第一個參數 "./changData" 指定了程序的路徑// 第二個參數 "changData" 是傳遞給程序的 argv[0],即程序名// 第三個參數 "config.txt" 是傳遞給 changData 程序的參數,指定要操作的文件// NULL 表示參數列表的結束execl("./changData", "changData", "config.txt", NULL);// 如果execl執行失敗,則會繼續執行以下代碼perror("Failed to execute changData"); // 打印執行失敗的原因exit(1); // 子進程失敗時退出}} else {printf("wait, do nothing\n"); // 如果輸入不是1,提示等待并什么也不做}}return 0; // 主程序循環,實際上這里永遠不會執行到
}
例子27? ? 根據輸入決定執行一個外部命令(changData),該命令與配置文件 config.txt 相關聯。如果用戶輸入 1,程序會創建一個子進程,該子進程通過 system 函數調用外部程序 ./changData 來處理文件 config.txt
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main()
{pid_t pid; // 用于存儲進程IDint data = 10; // 用戶輸入的數據初始化為10while(1) { // 無限循環,直到程序被外部方式終止printf("please input a data\n"); // 提示用戶輸入數據scanf("%d", &data); // 讀取用戶輸入的整數數據if(data == 1) { // 如果輸入的數據為1,則進行操作int fdSrc; // 文件描述符,雖然在此代碼版本中未被使用pid = fork(); // 創建子進程if(pid > 0) {wait(NULL); // 父進程等待子進程完成}if(pid == 0) { // 子進程代碼塊// 子進程執行一個外部程序 "changData" 通過 system 函數// "./changData config.txt" 是被調用的命令,傳遞 'config.txt' 作為參數system("./changData config.txt");exit(0); // 執行完外部命令后,子進程應正常退出}} else {printf("wait, do nothing\n"); // 如果輸入不是1,提示等待并什么也不做}}return 0; // 主程序循環,實際上這里永遠不會執行到
}
例子28? ??system() 執行系統命令(在本例中是 ps),這個命令用來列出當前運行的進程。然而,該代碼示例存在一個問題:它沒有捕獲 system() 調用的輸出
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函數原型:int execl(const char *path, const char *arg, ...);int main(void)
{char ret[1024] = {0}; // 定義一個字符數組并初始化所有元素為0,用于存儲輸出system("ps"); // 調用system函數執行ps命令,ps命令用于顯示當前運行的進程// 注意:system函數實際上不會將命令輸出存儲在ret數組中printf("ret=%s\n", ret); // 打印ret數組的內容,預期輸出為空字符串,因為system不會更改retreturn 0;
}
例子29? ?popen() 和 fread() 函數從 ps 命令獲取輸出并將其讀入到一個字符數組中。該程序展示了如何執行系統命令并捕獲其輸出,適合需要從命令行工具中直接讀取數據的場景
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// 函數原型:int execl(const char *path, const char *arg, ...);
// size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)int main(void)
{char ret[1024] = {0}; // 創建字符數組,用于存儲命令輸出FILE *fp; // 文件指針,用于執行 popen() 返回的流// 執行 'ps' 命令,并打開用于讀取的管道fp = popen("ps", "r");if (fp == NULL) { // 檢查 popen 是否成功打開了管道perror("Failed to run command"); // 打印 popen 執行失敗的錯誤詳情exit(1); // 退出程序}// 從 'ps' 命令的輸出流中讀取數據到 ret 數組中int nread = fread(ret, 1, 1024, fp); // 讀取最多 1024 個字節到 ret// 打印讀取的字節數和內容printf("read ret %d byte, ret=%s\n", nread, ret);// 關閉管道pclose(fp);return 0;
}
例子30? ?處理命令行參數。它通過遍歷 argc 和 argv 數組來打印所有傳遞給程序的參數
#include <stdio.h>int main(int argc, char *argv[]) // main 函數接受命令行參數:argc 表示參數數量,argv 是參數字符串數組
{int i = 0; // 定義循環計數變量for(i = 0; i < argc; i++) // 循環遍歷所有命令行參數{printf("argv[%d]: %s\n", i, argv[i]); // 打印每個參數的索引和內容}return 0; // 程序正常結束
}
例子31? ?等待用戶輸入。當用戶輸入 1 時,程序會創建一個子進程,這個子進程會修改一個文件(./file1)中特定字符串("LENG=")之后的字符
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>int main()
{pid_t pid; // 用于存儲進程IDint data = 10; // 用戶輸入的數據初始化為10while(1) { // 無限循環,直到程序被外部方式終止printf("please input a data\n"); // 提示用戶輸入數據scanf("%d", &data); // 讀取用戶輸入的整數數據if(data == 1) { // 如果輸入的數據為1,則進行操作pid = fork(); // 創建子進程if(pid > 0) {// 父進程執行的代碼塊// 父進程不做任何操作,繼續循環等待下一次輸入}else if(pid == 0) {// 子進程執行的代碼塊char *readBuf = NULL; // 讀緩沖區指針int fdSrc; // 文件描述符fdSrc = open("./file1", O_RDWR); // 打開文件file1進行讀寫操作int size = lseek(fdSrc, 0, SEEK_END); // 獲取文件大小lseek(fdSrc, 0, SEEK_SET); // 將文件指針重置到文件開始readBuf = (char *)malloc(sizeof(char) * size + 8); // 分配讀緩沖區內存int n_read = read(fdSrc, readBuf, size); // 讀取文件內容到緩沖區char *p = strstr(readBuf, "LENG="); // 在緩沖區中查找"LENG="if(p == NULL) {printf("not found\n"); // 如果沒有找到,打印未找到并退出exit(-1);}p += strlen("LENG="); // 移動指針到"LENG="之后*p = '5'; // 修改內容lseek(fdSrc, 0, SEEK_SET); // 將文件指針重置到文件開始int n_write = write(fdSrc, readBuf, strlen(readBuf)); // 將修改后的緩沖區內容寫回文件close(fdSrc); // 關閉文件free(readBuf); // 釋放分配的內存exit(0); // 子進程退出}}else {printf("wait, do nothing\n"); // 如果輸入不是1,提示等待并什么也不做}}return 0; // 主程序循環,實際上這里永遠不會執行到
}
例子32? ??execl()
函數是為了替換當前的進程映像為/bin/ls
命令的進程映像
#include <stdio.h> // 引入標準輸入輸出頭文件。
#include <stdlib.h> // 引入標準庫頭文件,用于執行一些常規的函數操作,比如exit()。
#include <unistd.h> // 引入UNIX標準函數定義頭文件,提供對POSIX操作系統API的訪問。// 函數原型聲明:int execl(const char *path, const char *arg, ...);
// execl()函數用于執行指定的文件路徑,將當前進程替換為一個新的進程。int main(void)
{printf("before execl\n"); // 在調用execl()前打印信息。// 調用execl()嘗試執行/bin/ls命令來列出目錄內容。"ls"是命令名,"-l"是參數。if(execl("/bin/ls", "ls", "-l", NULL) == -1){printf("execl failed!\n"); // 如果execl()返回-1,則說明執行失敗。perror("why"); // 使用perror()函數輸出錯誤原因。perror()會根據全局錯誤碼errno輸出錯誤描述。}// 如果execl()函數調用成功,則不會執行以下代碼,因為execl()會替換當前進程的映像,不會返回。printf("after execl\n"); // 如果execl()失敗,會繼續執行這里的代碼。return 0; // 程序正常結束。
}
例子33? ?vfork()
創建子進程并控制執行順序
#include <stdio.h> // 引入標準輸入輸出頭文件,用于printf函數。
#include <sys/types.h> // 引入數據類型定義,例如pid_t。
#include <unistd.h> // 引入POSIX操作系統API,例如vfork和getpid函數。
#include <stdlib.h> // 引入標準庫頭文件,用于執行一些常規的函數操作,如exit()。int main()
{pid_t pid; // 聲明一個pid_t類型的變量來存儲進程ID。int cnt = 0; // 計數器,用于子進程中記錄循環次數。pid = vfork(); // 創建一個子進程,子進程與父進程共享內存空間。if (pid > 0) // 如果pid大于0,表示當前代碼塊在父進程中執行。{while (1) { // 父進程無限循環。printf("cnt=%d\n", cnt); // 打印當前計數器的值(注意:這個值在父進程中不會改變)。printf("this is father print, pid = %d\n", getpid()); // 打印父進程的ID。sleep(1); // 暫停父進程1秒,以便觀察輸出。} }else if (pid == 0) { // 如果pid等于0,表示當前代碼塊在子進程中執行。while (1) { // 子進程無限循環。printf("this is child print, pid = %d\n", getpid()); // 打印子進程的ID。sleep(1); // 暫停子進程1秒,以便觀察輸出。cnt++; // 子進程中計數器遞增。if (cnt == 3) { // 如果計數器達到3,子進程退出。exit(0); // 調用exit函數,正常終止子進程。}} }return 0; // 主程序結束(通常這個部分不會被執行到,因為父子進程已經進入了無限循環)。
}