# | 數據流 |
0 | 鍵盤 |
1 | 屏幕 |
2 | 屏幕 |
描述符表的第一列是文件描述符號,另一列是它們對應的數據流,描述符表前三項恆古不變,0號標准輸入,1號標准輸出,2號標准錯誤輸出,其他項要么為空,要么為鏈接進程打開的數據流。
怎樣返回描述符
FILE * my_file = fopen("xxxx.txt", "r"); int p = fileno(my_file);
復制數據流
dup2(4,3);
將4號描述符的數據流連接到3號描述符
waitpid()函數在sys/wait.h頭文件中,作用是等子進程結束后在繼續運行父進程
waitpid(進程的pid, 這個變量用來保存進程信息(int指針變量),選項(一般設置為0,設置為0表示等待進程結束))
在第二個參數中會保存一個值,它會記錄進程完成情況,可以用WEXITSTATUS()來查看。
二.c語言中的錯誤處理代碼
每次系統調用時都需要寫錯誤處理代碼,即出現錯誤停止程序,並報錯。
exit()函數在stdlib.h頭文件中,它可以讓進程退出並設置退出狀態值
錯誤處理函數的例子:
void error (char * msg) { fprintf(stderr, "%s : %s\n", msg, strerror(errno)); exit(1); }
調用方法
pid_t pid = fork(); if(pid == -1) { error("無法克隆進程!"); }
二.在代碼中創建管道
pipe()函數創建兩條相連的數據流,與linux命令中的管道符號|效果相同
首先創建一個存儲兩個字符的數組,pipe()函數會創建一條管道並返回兩個描述符,一個描述符讀數據,一個描述符寫數據
int fd[2]; pipe(fd);
子進程把管道寫入端連到標准輸出
close(fd[0]) close()關閉管道的數據流 dup2(fd[1], 1); fd[1]向管道寫數據
父進程把讀取端連到標准輸入
dup2(fd[0], 0); close(fd[1]);
其中fd[0]從管道讀數據
一條管道只能單向通信,可以創建兩條管道進行雙向通信
可以反向連接管道從父進程到子進程
三.操作系統可以向程序發送信號
1.信號表如下:
信號名 | 作用 |
SIGINT | 進程被中斷 |
SIGQUIT | 有人要求停止進程,並且要求把存儲器中的內容保存到核心轉儲文件 |
SIGFPE | 浮點錯誤 |
SIGTRAP | 調試人員詢問進程執行到了哪里 |
SIGSEGV | 進程企圖訪問非法存儲器地址 |
SIGWINCH | 終端窗口的大小發生改變 |
SIGTERM | 有人要求內核終止進程 |
SIGPIPE | 進程在向一個沒有人讀的管道寫數據 |
2.在使用ctrl+c使用相當於操作系統向程序發送SIGINT信號,默認的信號處理器會調用exit()函數
3.sigaction是一個函數包裝器,它有一個函數指針,sigaction告訴操作系統進程收到某個信號時應該調用哪個函數。
sigaction的創建方法
struct sigaction xxxx; xxxx.sa_handler = 函數名字; sigemptyset(&action.sa_mask); 用掩碼過濾要處理的信號 xxxx.sa_flags = 0;一些附加標志位將它置0; return sigaction(信號編號, &xxxx, NULL);最后一個選項可以使用&變量名用來保存被替換的信號處理器
使用sigaction所包裝的函數叫做信號處理器,信號是一個整型值,如果你創建一個自定義的處理器它的形參需要接收一個整型值。
例如:
void diediedie(int sig) { puts("Goodbye cruel world......\n"); exit(1); }
4.使用kill殺死進程
kill 進程id 向程序發送SIGTERN
kill -INT 進程id 向程序發送SIGINT信號
kill -SEGV 進程id 向程序發送SIGSEGV
kill -KILL 進程id向程序發送SIGKILL信號
5.可以使用raise(信號名)函數讓程序向自己發送信號,可以在程序接收到低級別信號時引發更高級別的信號,這叫做信號升級。
6.使用定時器函數
alarm(時間數值以秒為單位)
一個進程最好只設置一個定時器
在n秒后發出SIGALRM信號
7.還原與忽略信號處理器
SIG_DFL以默認方式處理信號
SIG_IGN讓進程忽略某個信號
使用方法:
調用前面的使用sigaction注冊的處理器函數
函數名(信號,SIG_DEL)以默認方式處理信號
函數名(信號,SIG_IGN)忽略某個信號