1.進程回收資源空間
(1)wait函數
頭文件:
? ? ? ?#include <sys/types.h>
#include <sys/wait.h>函數接口:
? ? ? ?pid_t wait(int *wstatus);
功能:阻塞等待回收子進程的資源空間
參數:
wstatus :保存子進程消亡狀態的變量地址
NULL:不保存子進程退出的狀態
返回值:
成功:返回回收到的子進程的PID號
失敗:-1
wait(NULL);基本思想:
進程同步:允許父進程暫停執行,直到其子進程終止或改變狀態
資源回收:確保子進程終止后其資源被正確釋放(防止"僵尸進程")
狀態獲取:讓父進程能夠獲取子進程的退出狀態信息
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>int main(int argc, char const *argv[])
{int *p = malloc(sizeof(int));*p = 100;pid_t pid = fork();if(pid > 0){int wstatus;pid_t pidtmp = wait(NULL);printf("pidtmp = %d\n", pidtmp);/*if (WIFEXITED(wstatus)){printf("%d over normall, state : %d\n", pidtmp, WEXITSTATUS(wstatus));}else if (WIFSIGNALED(wstatus)){printf("%d ober by signal,signal num = %d\n", pidtmp, WTERMSIG(wstatus));}*/while(1){printf("ppid = %d, pid = %d, *p = %d\n",getpid(), pid, *p);sleep(1);}}else if(0 == pid){ int i = 10;while(i--){printf("pid = %d, ppid = %d, *p = %d\n", getpid(), getppid(), *p);sleep(1);}}else{perror("fork error");exit(0);}return 0;
}
(2)waitpid函數
搭配輪詢回收
函數接口:
pid_t waitpid(pid_t pid, int *status, int options);
? ?功能:回收指定進程的資源
和wait功能相似,比wait更靈活
?參數:
pid:
<-1 回收指定進程組內的任意子進程 (-100.等待GID=100的進程組中的任意子進程)
-1 回收任意子進程,組內外
0 回收和當前調用waitpid一個組的所有子進程,組內?
> 0 回收指定ID的子進程
status 子進程退出時候的狀態,
如果不關注退出狀態用NULL;
options 選項:
0 ?表示回收過程會阻塞等待
WNOHANG 表示非阻塞模式回收資源。
? ?返回值:? ? ? ? ? ? 成功 返回接收資源的子進程pid
失敗 ?-1
設定為非阻塞且沒有回收到子進程返回0?
(3)子進程資源空間回收策略
1. wait阻塞回收:一般情況下,父進程專門負責資源回收;
2. waitpid非阻塞方式回收:搭配輪詢方式回收。
3. 不回收:子進程的任務需要一直執行
4. 異步回收:當子進程結束時通知父進程進行回收
2.? exec : 函數族
(1)基本概念
在一個進程里面執行另外一個文件(可執行文件):
本質:將文本去的指令代碼替換成exec要執行的文件的指令。
算法思想:
不創建新進程:
與 fork() 不同,exec 不會創建新進程,只是替換當前進程的內容
參數傳遞多樣性:
列表形式(execl, execlp, execle):以 NULL 結尾的可變參數列表
數組形式(execv, execvp, execvpe):通過字符串數組傳遞參數
函數 關鍵特點 execl
路徑+參數列表形式,需要完整路徑 execlp
文件名+參數列表形式,會在 PATH 環境變量中查找可執行文件 execle
路徑+參數列表+自定義環境變量形式 execv
路徑+參數數組形式,需要完整路徑 execvp
文件名+參數數組形式,會在 PATH 環境變量中查找可執行文件 execvpe
文件名+參數數組+自定義環境變量形式
(2)函數接口
?int execl(const char *path, const char *arg, ...? ?/* (char ?*) NULL */);
參數:
path:要執行的可執行文件的路徑和名稱
arg:執行該可執行文件時需要傳遞的參數
NULL :參數傳遞結束標志
返回值:
出錯:-1?int execlp(const char *file, const char *arg, ...? ?/* (char ?*) NULL */);
功能:從PATH指定的系統路徑下尋找該可執行文件
參數:
file:需要執行的可執行文件的名稱(系統路徑下已有的文件)
arg : 執行該可執行文件時需要傳遞的參數? ? ? ?int execle(const char *path, const char *arg, ...?/*, (char *) NULL, char * const envp[] */);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);l:list ?列表
p:path ?路徑 : 系統路徑
v:vector 容器
e:env ?環境變量
#include <stdio.h>
#include <unistd.h>int main(int argc, char const *argv[])
{//execl("/usr/bin/pstree", "pstree", "-p", NULL);char *arg[] = {"ls", "-l", NULL};//execv("/bin/ls", arg);//execlp("ls", "ls", "-l", NULL);execvp("ls", arg);return 0;
}
3.system函數
system 通過 fork-exec 啟動 shell 來執行命令(支持管道/重定向等 shell 特性),并自動處理進程等待和信號,返回命令的退出狀態;而 exec 直接替換當前進程為指定程序(不啟動 shell,無返回),需配合 fork 使用并手動管理子進程。
與exec函數族關鍵區別:
shell 處理:system 調用 /bin/sh 解析命令,exec 直接執行程序。
進程控制:system 阻塞等待命令完成,exec 替換當前進程(若成功則不返回)。
返回值:system 返回命令狀態,exec 僅在失敗時返回(成功則執行新程序)。
使用場景:system 適合簡單命令調用,exec 適合精確控制進程替換。
用execl函數實現system函數
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>int main(int argc, char const *argv[])
{pid_t pid = fork();if(pid > 0){printf("pid = %d",getpid());}else if(0 == pid){ printf("pid = %d\n", getpid());execl("/bin/ls", "ls", "-l", NULL);}else{perror("fork error");exit(0);}pid_t pidtmp = wait(NULL);printf("pidtmp = %d\n", pidtmp);return 0;
}
4.線程的基本概念
1. 什么是線程
輕量級的進程,可實現多任務的并發。
進程是操作系統資源分配的最小單位;
線程是操作系統任務調度的最小單位。? ??
2. 線程的創建
線程由某個進程創建。
進程創建線程時,會為其分配獨立的(8M)棧區空間;
線程和所在進程,以及進程中的其他線程,共用進程的堆區、數據區、文本區。3. 線程的調度
宏觀并行,微觀串行 ? ??4. 線程消亡
1. ?線程退出
2. 回收線程資源空間
5.進程與線程的區別
進程:
? ? ? ? ? ?進程是操作系統資源分配的最小單位;
資源消耗:進程資源開銷大,每次創建都需要有0-4G的虛擬內存空間 ??
效率角度:由操作系統創建,創建時耗時比線程大;跨進程調度比跨線程調度慢;
通信方面: 進程間不能直接通信,需要使用進程間通信機制(IPC機制)
安全性角度:進程安全性比線程高,各進程空間獨立? ? ?
線程:
? ? ? ? ? ? ? 線程是操作系統任務調度的最小單位。
資源消耗:資源開銷較小,只需要所在進程為其開辟8M的棧區空間
效率角度:由所在進程創建;跨進程調度比跨線程調度慢;
通信方面:通信簡單,可以使用線程共享的區域進行通信(比如全局變量)
安全性角度:線程沒有進程安全性好,一個線程異常可能影響同一進程中的所有線程
6.線程的相關編程
(1)線程的創建
頭文件:
? ? ? ? ? ? #include <pthread.h>
函數接口:
? ? ? ?int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
功能:創建一個新的線程
? 參數:
thread : 保存線程ID的變量地址
attr:線程屬性的對象地址
NULL : 按照默認屬性創建
start_routine:函數的指針:指向線程啟動后要執行的任務(線程任務函數)
arg:為線程任務函數傳遞的參數
? ? ?返回值:
成功:0
失敗:非0
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>void *tash(void *arg)
{printf("tid = %ld\n", pthread_self());
}int main(int argc, char const *argv[])
{pthread_t tid;int ret = pthread_create(&tid, NULL, tash, NULL);if(ret != 0){printf("pthread create error\n");return -1;}sleep(2);return 0;
}
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>typedef struct stu
{int id;char name[32];float score;
}stu_t;void *tash(void *arg)
{stu_t *s = (stu_t *)arg;printf("id = %d, name = %s, score = %f\n", s->id, s->name, s->score);printf("tid = %ld\n ", pthread_self());
}int main(int argc, char const *argv[])
{pthread_t tid;stu_t s = {1, "laoliu", 99.9};int ret = pthread_create(&tid, NULL, tash, &s);if(ret != 0){printf("pthread create error\n");return -1;}sleep(2);return 0;
}