回調函數:
atexit()
原型:? ? ? ? int atexit(void (*function)(void));
功能:? ? ? ? 注冊進程退出前執行的函數
參數:? ? ? ? @function? ? ? ? 函數指針,指向void返回值void參數的函數指針
返回值? ? ? ? 成功 返回0
? ? ? ? ? ? ? ? ? ?失敗 返回非0
當注冊調用exit或者由main函數執行return時,所有用atexit注冊的退出函數,將會由注冊時順序被調用
代碼示例:
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>FILE* fp;
char* p;
void clean()
{printf("clean fun ,p is %s\n", p);fclose(fp);free(p);
}int main(int argc, char** argv){atexit(clean);fp = fopen("1.txt", "r");p = malloc(50);strcpy(p, "hello");printf("process will end..\n");return 0;
}
進程空間的回收
wait() / waitpid()
原型:? ? ? ? pit_t wait(int *status);? ? ? ? //阻塞回收(等待子進程結束再回收)
功能:? ? ? ? 該函數可以阻塞等待任意子進程退出并回收該進程的狀態(一次回收一個子進程)
? ? ? ? ? ? ? ? ? ? ? ? //一般用于父進程回收子進程的狀態
參數:? ? ? ? @status? ? ? ? 進程退出時候的狀態
? ? ? ? ? ? ? ? ? ? ? ? //如果不關心其退出狀態一般用NULL表示
? ? ? ? ? ? ? ? ? ? ? ? //如果要回收進程退出狀態(正常退出 / 異常退出),則用WEXITSTATUS回收
返回值? ? ? ? 成功 返回回收的子進程的pid
? ? ? ? ? ? ? ? ? ?失敗 返回-1
1)如果所有的子進程都在運行,在阻塞
2)如果一個子進程終止,正在等待的父進程則獲得終止狀態,獲得子進程的狀態后,立刻返回。
3)如果沒有子進程,則立即出錯退出。4)由父進程調用,回收子進程的pcb,會阻塞,父進程回收資源的時候,子進程沒有退出。父進程就會等待子進程結束再回收。
waitpid(-1, status, 0) = wait(status)
原型:????????pid_t waitpid(pid_t pid, int status);? ? ? ? //非阻塞回收
功能:????????用于等待特定子進程的狀態變化
參數:? ? ? ? @pid
? ? ? ? ? ? ? ? ? ?@status
int status;
waitpid(pid, &status, 0);// 檢查宏:? ? ? ? //三組宏兩兩一組配合使用
WIFEXITED(status) ? ?// 子進程正常退出
WEXITSTATUS(status) ?// 獲取退出狀態碼
WIFSIGNALED(status) ?// 子進程被信號終止
WTERMSIG(status) ? ? // 獲取終止信號編號
WIFSTOPPED(status) ? // 子進程是否被暫停
WSTOPSIG(status) ? ? // 獲取暫停信號編號
返回值
? ? ? ??
代碼示例:
//<1>完整使用示例
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>int main(int argc, char **argv)
{pid_t pid = fork();if (pid > 0){printf("father pid:%d, child pid:%d\n", getpid(), pid);int status;while (1){//非阻塞回收pid_t recycle_pid = waitpid(pid, &status, WNOHANG); if (pid == recycle_pid) {printf("recycle_pid:%d\n", recycle_pid);//子進程正常結束if (WIFEXITED(status)){printf("child ret value is %d\n", WEXITSTATUS(status));}else if (WIFSIGNALED(status)){printf("child unnormal,signal is %d\n", WTERMSIG(status));}break;}else if (0 == recycle_pid) //子進程未結束{printf("子進程未結束...\n");usleep(1000*500);//0.5s}else{printf("waitpid error...\n");break;}}}else if (0 == pid){int i = 10;while (i--){printf("I'm processing....\n");sleep(1);}exit(20);}else{perror("fork error\n");return 1;}return 0;
}
//<2>非阻塞回收制定進程
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>int main(void)
{int id = 2;int n = 0;printf("n = :");scanf("%d", &n);pid_t pid[5] = {0};//創建5個子進程while (n--){pid[n] = fork();if (pid[n] > 0){continue;}else if (0 == pid[n]){printf("%d pid:%d\n",n, getpid());sleep(rand() % 5+1);exit(20);}else{perror("fork err...\n");return 1;}}//回收id = 2的進程while (1){pid_t recycle_pid = waitpid(pid[id-1], NULL, WNOHANG);if(pid[id-1] == recycle_pid) //回收成功,相當于recycle_pid > 0{printf("recycle_pid: %d success\n",recycle_pid);break;}else if(0 == recycle_pid) {}else //recycle_pid<0,回收失敗{printf("recycle_pid failure....\n");}}return 0;
}
exec族
? ? ? ? 功能:用fork創建子進程后執行的是和父進程相同的程序 (但有可能執行不同的代碼分支)
子進程往往要調用一種exec函數以執行另一個程序。當進程調用一種exec函數時,該進程的
用戶空間代碼和數據完全被新程序替換,從新程序的啟動例程開始執行。調用exec并不創建
新進程,所以調用exec前后該進程的id并未改變。
其實有六種以exec開頭的函數,統稱exec函數:
頭文件:#include <unistd.h>
!!!調用非系統可執行程序,第一個參數都傳路徑+文件名
原型:????????int execl(const char *path, const char *arg, ...,/* (char ?*) NULL */);? // l :list
參數:????????@path? ? ? ? 可執行程序的路徑
? ? ? ? ? ? ? ? ? ?@arg? ? ? ? 參數 [字符串的形式] 列表,可以有多個?
? ? ? ? ? ? ? ? ? ?@NULL? ? ? ? 參數結束標志(不能省)
示例:execl("/bin/ls", "ls","-a","-l","--color == auto",NULL);
原型:????????int execlp(const char *file, const char *arg, ...,/* (char ?*) NULL */);? //p: PATH
參數:????????@file? ? ? ? 文件名(在系統路徑$PATH 下可以找到)? ? ? ? //命令:echo $PATH
? ? ? ? ? ? ? ? ? ?@arg? ? ? ? 參數 [字符串的形式] 列表,可以有多個?
? ? ? ? ? ? ? ? ? ?@NULL? ? ? ? 參數結束標志(不能省)
示例:
?PATH 系統環境變量 查看命令:echo $PATH
execlp("ls", "ls", "-a", "-l", "--color=auto", NULL);
原型:????????int execv(const char *path, char *const argv[],NULL);? ? ? ? // v:vector(數組)
參數:????????@path? ? ? ? 可執行程序的路徑
? ? ? ? ? ? ? ? ? ?@arg? ? ? ? 參數 [字符串的形式] 列表,可以有多個?
? ? ? ? ? ? ? ? ? ?@NULL? ? ? ? 參數結束標志(不能省)
示例:
char *const args[] = {"cp", "11exec.c", "cp.txt",NULL};
execv("/bin/cp", args);
原型:???????? int execvp(const char *file, char *const argv[],NULL);? // vp: vector path? ? ? ??
參數:????????@file? ? ? ? 文件名(在系統路徑$PATH 下可以找到)???????? //命令:echo $PATH
? ? ? ? ? ? ? ? ? ?@arg? ? ? ? 參數 [字符串的形式] 列表,可以有多個?
? ? ? ? ? ? ? ? ? ?@NULL? ? ? ? 參數結束標志(不能省)
示例:
char *const args[] = {"cat","11exec.c",NULL};
execvp(args[0], args);
??