- 相關接口
????pause 函數用于將進程掛起. 如果信號的處理動作是終止進程, 則進程終止, pause 函數沒有返回值; 如果信號的處理動作是忽略, 則進程被掛起, pause函數不返回, 如果信號的處理動作是捕捉, 則調用信號處理動作之后pause 返回 -1. - 來看一段代碼
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>void sig_alarm(int seconds)
{}
int mysleep(int seconds)
{struct sigaction act;struct sigaction oact;int unslept = 0;act.sa_handler = sig_alarm;act.sa_flags = 0;sigemptyset(&act.sa_mask);sigemptyset(&oact.sa_mask);sigaction(SIGALRM, &act, &oact);alarm(seconds);pause();unslept = alarm(0);sigaction(SIGALRM, &oact, NULL);
}
int main()
{while(1){mysleep(5);printf("5 seconds after\n");}return 0;
}
??????????????????????????????
????上面代碼是用來自主實現一個 sleep 函數. 先將 SIGALRM 信號注冊,然后設定一個鬧鐘, 接著系統調用 pause 函數等待, 在 nsecs 秒之后, 鬧鐘設定的時間到了, 此時內核給進程發送一個 SIGALRM 信號, 當內核正要切回到用戶態時, 發現一個可以遞達的信后 SIGALRM, 它的處理動作是 sig_alrm, 此時內核有切回到 這個函數處取執行該信號的自定義動作, 在處理 sig_alrm 函數時, 系統將 SIGALRM 信號屏蔽, 當處理完這個函數時, 對 SIGALRM 函數解除屏蔽, 同時系統通過調用 sigreturn 函數返回到內核態, 接著從內核態返回到 主控制流處, 執行剩余的代碼
????(1)也許會有人問信號處理 sig_alrm 函數時什么都沒有干為什么還要注冊, 原因很簡單, 如果對 SIGALRM 信號不注冊, 當注冊一個 5 秒的鬧鐘信號時,5 秒之后該信號會被遞達, 而此時的信號沒有注冊,信號的處理動作將會是終止進程, 此時進程終止, 程序退出, 而我們要實現的是將進程睡眠 5 秒鐘, 那不就和我們的目的有沖突了嗎?
????(2)也許還會有人問, 為什么在sleep函數之后需要對 SIGALRM 信號的默認處理動作進行恢復, 原因很簡單. 加入這個代碼很長, 而我們在 sleep 函數之后系統又用到了 SIGALRM 信號, 而此時我們的目的是在 n 秒之后操作系統給進程發送一個 SIGALRM 信號來終止信號, 而此時我們沒有將該信號的處理動作進行恢復, 進程會去執行 sig_alrm 函數, 此時進程就不會在 5 秒之后退出
3. 可重入函數
????(1)定義 :
????????重入的意思就是函數在被不同的執行流調用, 有可能在第一個執行流還沒有執行完的時候又被第二個執行流調用. 而此時可能會由于重入導致一些錯誤, 此時的函數稱為不可重入函數, 而當第一個執行流還沒有執行完時, 第二個執行流進入, 此時沒有導致函數執行功能發生錯誤, 此時這個函數就叫做可重入函數.
????(2)條件:
????????如果一個函數調用了 malloc , free, 或者標準庫 I/O函數,等全局變量的時候這個函數就叫做不可重入函數, 而如果一個函數只調用了自己的局部變量, 此時的函數叫做可重入函數,因為系統函數和主控制流各自獨立擁有自己的堆棧, 不存在調用關系, 因此兩個互不干擾