目錄
一、進程
? ? ? ? 1.程序和進程
? ? ? ? 2.進程的八種狀態
????????3.? ? ?幾個狀態
? ? ? ? 4.關于進程常用命令
二、關于進程的函數
? ? ? ? 1.fork
? ? ? ? 2.面問
????????3.孤兒進程? 后臺進程
? ? ? ? 2.? ?exec函數族 (只保留父子關系,做新的事情)??
? strtok函數?
三、進程的結束
1.分類
exit和_exit的區別?
wait函數?
?waitpid函數?
四、總結
一、進程
? ? ? ? 1.程序和進程
????????內存中正在進行(運行)中的程序。
????????./a.out跑起來就是a.out對應的進程。
?????????程序 靜態 硬盤
? ???????進程 動態 內存
? ? ? ?
????????程序= 代碼 + 數據= 代碼區(text段)+棧區+堆區+BSS+Data
????????進程 = 代碼區(text段)+棧區+堆區+BSS+Data + PCB(Process Control Block)
? ? ? ? BSS:存放程序中未初始化的全局變量的一塊內存區域。
? ? ? ? DATA:存放程序中已初始化的全局變量的一塊內存區域。
? ? ? ? 2.進程的八種狀態
? ? ? ? *D??不可中斷態的睡眠態
? ? ? ? *R? 正在運行態? ? 或者? ?就緒態??
? ? ? ? *S? 可終端的睡眠態
? ? ? ? *T? stopped by job control signal
? ? ? ? ?t??stopped by debugger during the tracing
? ? ? ? ?X? 死亡態
? ? ? ??*Z? 僵尸態
????????3.? ? ?幾個狀態
??????
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?通用三態圖?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? linux系統的狀態
? ? ? ? 4.關于進程常用命令
? ? ? ? top? ?動態查看系統中進程
????????pstree -sp [pid]? ? ?查看進程樹(可指定pid號)
????????kill? ?發出信號? ? ? ?
????????????????kill -l ?//查看可以發送的信號
? ? ? ????????18) SIGCONT? //繼續信號
? ? ? ????????19) SIGSTOP? //暫停
? ? ????????? ?9) SIGKILL? //死亡信號,殺死進程
? ? kill -19 [pid] //給指定pid號的進程發送 信號
????????ps aux | grep a.out? ? ?查看pid號進程的狀態信息
????????ps -eLf | grep a.out? ? ? 查看pid和ppid號
二、關于進程的函數
? ? ? ? 1.fork
? ? ? ? ???pid_t fork(void);? ? 通過復制主調進程創建子進程。
????????一次fork返回了兩次? ? ? ? typedef? ?int? ? pid_t?
?? 成功 在父進程空間返回子進程pid,在子進程空間返回 0
? ?失敗? ? 父進程返回值-1? ? ? ?errno會被設置?
? ? ? ? 2.面問
? ? ? ? eg1如果兩次fork同時前后執行,會生成幾個進程?
? ? ? ? ? ? ? ? 4個進程
? ? ? ? eg2? ?fork()&&fork()||fork();
? ? ? ? ? ? ? ? 5個進程
? ? ? ? ? ? fork()
? ? ? ? ? /? ? ? ? ? ?\
? ? ?fork()? ? ? ? fork1()
? ? ?/ ?\? ? ? ? ? ? ? ? / ? ?\
? fork ?fork2 ?fork1 fork3
? ? ? ? ?? / ? \
? ? ? fork2 ?fork4
????????3.孤兒進程? 后臺進程
????????子進程沒有父進程就是孤兒進程,將會有 init(1)-進程 收養子進程。變成 后臺進程 (?ctrl + c) 這個信號只能發給前臺進程。? 結束后臺進程要用kill
????????子進程結束,但是父進程,沒有對子進程收尸。那就是僵尸進程。僵尸態是有危害的,消耗內存。
? ?eg1? ? ? fork創建子進程,分別打印pid
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(void)
{pid_t pid = fork();if (pid < 0){perror("fork fail");return -1;}if (pid > 0){printf("father pid = %d ---\n",getpid());printf("pid = %d",getpid());}else if (pid == 0){printf("child pid = %d ---\n",getpid());}printf("--pid = %d --end---\n",getpid());return 0;
}
? ? ? ? 2.? ?exec函數族 (只保留父子關系,做新的事情)??
? ? ? ? ? ? ? ? 通過將新進程的各個段替換當前進程的各個段來實現,用來執行一個新的功能
????????????????int execl(const char *path, const char *arg, .../* (char ?*) NULL */);
? ? ? ? ? ? ? ?int execv(const char *path, char *const argv[]);?? ? ? ? ? ?????????@path ? 代表要運行的新程序的名字 要包含路徑
? ? ? ? ? ? ????????? ? ? eg:
? ? ? ? ? ? ? ? ? ? ?"/home/linux/fileio/mycp"
? ? ? ? ? ?????????@arg ? 表示要運行的程序的名字
? ? ? ? ? ? ? ? ????????? eg:
? ? ? ? ? ? ? ? ? ? ?"mycp"
? ? ? ? ? ?????????@... ?可變參數(要執行程序用到的參數)
? ? ? ? ? ? ? ? ?????????eg:
? ? ? ? ? ? ? ? ? ?"src.txt","dest.txt",NULL結尾
? ? ? ? l(list)和v(vector)的區別? 傳參的方式不同
? ? ? ? ??execl( "/home/linux/fileio/mycp","mycp", "src.txt","dest.txt",NULL);
? ? ? ? ? char * const args[] = {"mycp", "src.txt","dest.txt",NULL};
? ? ? ? ? int execv( "/home/linux/fileio/mycp", args);
? ? ? ? ???printf("---exec---code---");后續代碼不執行,因為段被替換
? ? ? ?????????int execlp(const char *file, char *const argv[]);
? ? ? ?????????int execvp(const char *file, char *const argv[],char *const envp[]);????????????????p 表示 PATH系統環境變量(系統運行時侯需要的一些變量)
????????????????表示要執行的可執行文件到PATH環境變量中去尋找
????????????????execlp("ls","ls","-l","/",NULL);
? ? ? ? ? ? ? ? char *const args[] = {"ls","-l","/",NULL};
? ? ? ? ? ? ????execlp("ls","ls","-l","/",NULL);
????????
? ? ? ? ? ?int execle(const char *path, const char *arg, .../*, (char *) NULL, char * const envp[] */);? ?看要運行的程序需不需要環境變量,需要就可以傳。不需要的話用之前的方式運行起來就行。
? ? ? ? ? ?int execvpe(const char *file, char *const argv[],char *const envp[]);
? ? ? ? ? e 表示用戶環境變量 ---提供了一種方式,可以給要運行的程序傳遞環境變量
? ? ? ? ? ?extern char **environ;
? ? ? ? ? ? int main{
? ? ? ? ? ? ? ? ? ?execle("/usr/bin/env","env",NULL,environ);
? ? ? ? ? ? ? ? ? ?char *const my_env[] = {"USERNAME=linux","PSWD=123456?",NULL};
????????????????? ?execle("/usr/bin/env","env",NULL,my_env);
? ? ? ? ? ? ? ? ? ?execvpe("env",my_env,NULL);
? ? ? ? ? ? ? ? ? ?return 0;
}
? ? ? ? ? ? ??
? strtok函數?
????????作用,提取字符串
????????char *strtok(char *str, const char *delim);
????????
? ????????? @str ? --- 要提取完整字符串 ? -- buf
? ? ? ? ? ? ? ?如果連續的分割 ?填NULL
? ????????? @delim --- 分隔標志 // " ;,"可以有多個分割標志
? ?
? ????????? 返回值:
? ????????? ? 成功 返回提取到的字符串的地址
? ????????? ? 失敗 NULL
eg? ? strtok的使用?
#include<stdio.h>
#include<string.h>
int main(int argc, char const *argv[])
{char buf[1024]={"ls -l ;/"};
#if 0 char *s1 = strtok(buf," ;");printf("s1 = %s\n",s1);char *s2 = strtok(NULL," ;");printf("s2 = %s\n",s2);char *s3 = strtok(NULL," ;");printf("s3 = %s\n",s3);
#endifchar *s[5] = {NULL};int i= 0;s[i] = strtok(buf," ;");while (s[++i] = strtok(NULL," ;"));for ( i = 0; i < 5; ++i){printf("s[%d]=%s\n",i,s[i]);}return 0;
}
eg1? ?實現一個shell程序
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>int main(int argc,const char *argv[])
{char buf[1024] = {0};while (1){printf("myshell$ ");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] = '\0';if (strncmp(buf,"exit",4) == 0 || strncmp(buf,"quit",4) == 0){printf("exit---myshll---\n");return 0;}int i = 0;char *arg[10] = {NULL};arg[i] = strtok(buf," ");while (arg[++i] = strtok(NULL," "));
#if 0for (i = 0; i < 10; ++i){printf("%d:%s\n",i,arg[i]);}
#endif pid_t pid = fork();if (pid < 0){perror("fork fail");return -1;}if (pid > 0){wait(NULL);continue;}else if (pid == 0){if (execvp(arg[0],arg) < 0){perror("execvp fail");return -1;}}}return 0;
}
?
三、進程的結束
1.分類
正常結束:
? ? ? ? 1)main 中 return
? ? ? ? 2)exit() //庫函數
? ? ? ? ? ?c庫函數,會執行io庫的清理工作,關閉所有 的流,以及所有打開的文件。
? ? ? ? ? ?注冊清理函數(atexit)。
? ? ? ? 3)_exit,_Exit 會關閉所有的已經打開的文件,不執行清理函數。 //系統調用
? ? ? ? //4) 主線程退出 ?
? ? ? ? //5)主線程調用pthread_exit
? ? ? ?? ? ? ?異常終止:
? ? ? ? 6)abort() //發送一個SIGABRT
? ? ? ? 7)signal ?//發信號 結束了進程 ?kill pid ?-9
? ? ? ? //8) 最后一個線程被pthread_cancle
? ? ?exit函數
? ? ? #include <stdlib.h>
? ? ? ?void exit(int status);
? ? ? ? ?功能:
? ? ? ? ? ? 造成進程正常結束
? ? ? ? ?參數:
? ? ? ? ? ?@status ? 帶出一個狀態值給到父進程? 結合wait和宏才能查看狀態值
return 0 自動調取一個exit函數,從而調用atexit函數,_exit不調用atexit函數
_exit
? ? ? ? #include <unistd.h>
? ? ? ?void _exit(int status);
? ? ? ? ?功能:
? ? ? ? ? ? 造成進程正常結束 ,立刻結束
? ? ? ? ?參數:
? ? ? ? ? ?@status ? 帶出一個狀態值給到父進程? ?結合wait和宏才能查看狀態值
exit和_exit的區別?
區別:
? ?exit 是庫函數
? ? ? 退出前,
? ? ? 1.先清理IO緩存
? ? ? 2.調用清理函數
? ?_exit 是系統調用
? ? ? 立即結束進程
atexit
? ? ? ?#include <stdlib.h>
? ? ? ?int atexit(void (*function)(void));
? ? ? ?
? ? ? ?功能:
? ? ? ? ? 注冊一個退出清理函數
? ? ? ?參數:
? ? ? ? @function ---- 函數指針
? ? ? ? ? ? ? ? ? ? ? ?函數類型 ?void func1(void)
? ? ? ?
? ? ? ?返回值:
? ? ? ? 成功 返回0
? ? ? ? 失敗 非0
? ? ? ? ps注冊順序和調用順序相反(有棧的結構)
????????
狀態值:
? ?status & 0377 ?=> 一個字節的數據
? ?
? ? 1 1 1 1 1 1 1 1 ?//0377 二進制
? ?
? ? 0 0 0 0 0 0 0 0
? ?
? ? //數值 個數 256 個值
? ?
wait函數?
????????pid_t wait(int *wstatus);
?????????用于等待子進程的狀態的變化,并獲取一些該子進程的信息。
? ? ? ? 三種變化
? ? ? ? 1.子進程結束?
????????2.子進程被信號暫停(kill? ?SIGSTOP)
? ? ? ? 3.子進程因信號被回恢復(SIGCONT)
? ? ? 參數:
? ? ? ? @status? 獲取子進程退出時的狀態信息(要用宏才能提取出來)? ?//被調修改主調的方式
? ? ? 返回值:
? ? ? ? 成功 返回狀態改變了的子進程的pid
? ? ? ? 失敗 -1
?????????如果不關心其退出狀態一般用NULL表示
? ?
? ? 注意:
? ? ? ?wait 本身是個阻塞操作(只有有子進程時,才阻塞,沒有子進程時,立即返回wait調用失敗) //子進程結束
? ? ? ? 父進程在子進程結束后用wait進行資源回收和狀態的獲取稱為"關心"。
? ? ? ? 不進行資源回收的結束的子進程是僵尸態。
? ? ? ?
? ? 宏:
? ?
? ? //正常結束
? ? ? ?WIFEXITED(wstatus) ? //判斷子進程是否是正常結束
? ? ? ? ? ? ? ? ? ? ? ? ? ? //正常結束 則為真 ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ?WEXITSTATUS(wstatus) //使用這個宏去那返回值
? ? ? ?
? ? //異常結束
? ? ? ?WIFSIGNALED(wstatus) //判斷子進程是否是被信號結束
? ? ? ?WTERMSIG(wstatus) //獲得 結束子進程的那個信號編號
eg 1? ??WIFEXITED(wstatus)和? WEXITSTATUS(wstatus)
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>int main(void)
{pid_t pid = fork();if (pid < 0){perror("fork fail");return -1;}if (pid > 0){sleep(3);printf("---wait----child---\n");int status;wait(&status);printf("status = %d\n",status);if (WIFEXITED(status)){printf("child status = %d\n",WEXITSTATUS(status));}}else if (pid == 0){printf("---child----exit---\n");exit(99);}return 0;
}
?eg 1? ??WIFSIGNALED(wstatus) 和 WTERMSIG(wstatus)
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>int main(void)
{pid_t pid = fork();if (pid < 0){perror("fork fail");return -1;}if (pid > 0){sleep(3);printf("---wait----child---\n");int status;//wait(&status);//waitpid(-1,&status,WNOHANG);waitpid(-1,&status,0);printf("status = %d\n",status);if (WIFEXITED(status)){printf("child status = %d\n",WEXITSTATUS(status));}}else if (pid == 0){printf("---child----exit---\n");exit(99);}return 0;
}
eg3?? ? wait的使用
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>int main(void)
{pid_t pid = fork();if (pid < 0){perror("fork fail");return -1;}if (pid > 0){ sleep(3);printf("---wait----child---\n");int status;wait(&status);printf("status=%d\n",status);if(WIFEXITED(status)){printf("child status = %d\n",WEXITSTATUS(status));}}else if (pid == 0){printf("---child----exit---\n");exit(99);}return 0;
}
?eg4? ?無人機狀態模擬
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>void do_fly(void)
{int i = 0;while (i < 5){printf("---%s---\n",__FUNCTION__);++i;sleep(1);}exit(88);
}void do_video(void)
{int i = 0;while (i < 3){printf("---%s---\n",__FUNCTION__);++i;sleep(1);}exit(77);
}
void do_transmit(void)
{int i = 0;while (i < 4){printf("---%s---\n",__FUNCTION__);++i;sleep(1);}exit(66);
}
void do_store(void)
{int i = 0;while (i < 6){printf("---%s---\n",__FUNCTION__);++i;sleep(1);}exit(55);
}int main(void)
{int i = 0;pid_t pid = 0;for (i = 0; i < 4; ++i){pid = fork();if (pid < 0){perror("fork fail");return -1;}if (pid == 0)break;}if (pid > 0){int status;for (i = 0; i < 4; ++i){wait(&status);if (WIFEXITED(status)){switch(WEXITSTATUS(status)){case 55:printf("do_store exit---\n");break;case 66:printf("do_transmit exit---\n");break;case 77:printf("do_video exit---\n");break;case 88:printf("do_fly exit---\n");break;}}}}else if (pid == 0){switch(i){case 0:do_fly();break;case 1:do_video();break;case 2:do_transmit();break;case 3:do_store();break;}}return 0;
}
?waitpid函數?
? ? ?pid_t? waitpid(pid_t pid, int *wstatus, int options);
? ? ? ?功能:
? ? ? ? ? 等待子進程狀態改變
? ? ? ?參數:
? ? ? ? ?@pid ? ? ? ?
? ? ? ? ? ? ? ?< -1 ? meaning wait for any child process whose process group ID is equal to the absolute value of pid.
? ? ? ? ? ? ? ? ?eg: -100
? ? ? ? ? ? ? ? ? ?表示等待 進程組ID 為 |-100| 這個進程組中的任意子進程
? ? ? ? ? ? ? ?-1 ? ? meaning wait for any child process.
? ? ? ? ? ? ? ? ? ?表示等待 當前父進程的任意子進程
? ? ? ? ? ? ? ?0 ? ? ?meaning wait for any child process whose process group ID is equal to that of the calling process.
? ? ? ? ? ? ? ? ? ?等待 進程組ID 等于 父進程pid的那個進程組中的任意子進程 ? ? ? ? ? ?
? ? ? ? ? ? ? ?> 0 ? ?meaning wait for the child whose process ID is equal to the value of pid.
? ? ? ? ? ? ? ? ? eg: 100
? ? ? ? ? ? ? ? ? ? ? 等待 進程pid 為 100的這個子進程狀態改變
? ? ? ? ?@wstatus ?//與wait的參數類似? ??如果不關心其退出狀態一般用NULL表示
? ? ? ? 獲取準確狀態值也是用
? ? ? ? ?@options ?//
? ? ? ? ? ? ? ? ? ?0 ? ? ? ? //阻塞調用
? ? ? ? ? ? ? ? ? ?WNOHANG ? //非阻塞? ?不斷的看子進程狀態有沒有改變,沒有改變就返回了。有改變了,將資源回收,并進行if判斷下面的操作。
? ? ? ?
? ? ? ?
? ? ? ?waitpid(-1, &wstatus, 0); ?//等價于 wait(&wstatus)
四、總結
//進程
創建 ?--- fork
運行
? ?//1.跟父進程類似 事情 ?
? ?//2.獨立運行一個新程序 ---exec函數
? ?//3.運行多個不同任務
結束
? ?正常結束 ?
? ? ?//1.return //main
? ? ?//2.exit
? ? ?//3._exit
? ?異常結束
? ? ?//4.abort ?//信號
? ? ?//5.signal //發其它信號
進程結束是兩種特殊狀態
? ?孤兒進程 ?
? ?僵尸進程 ? --- wait/waitpid ?