1. 程式人生 > >pause、jobs、setitimer(2)、system v ipc(day12)

pause、jobs、setitimer(2)、system v ipc(day12)

ssa 周期 types.h ros system signed job 功能 chl

一、pause(2)的使用
#include <unistd.h>
int pause(void);
功能:等待信號的到來
返回值:
-1  錯誤   errno被設置
只有在信號處理函數執行完畢的時候才返回。

利用所學的知識,編碼實現sleep函數的功能。
unsigned int psleep(unsigned int seconds);
代碼參見    psleep.c

二、信號從產生到處理的全過程
1、進程正在運行,按下ctrl+c鍵
2、ctrl+c是硬件中斷,使用進程切換到內核態。
3、驅動程序將ctrl+c鍵解釋為2號信號
4、在內核態中將進程的PCB的2號信號設置為1.繼續執行
5、當進程從內核態回到用戶態的時候,檢測進程的PCB中有哪些信號到達?如果沒有信號到達,直接切換回用戶態。如果有信號到達,調用信號的相關處理函數。信號處理函數執行完畢的時候,調用sigreturn(2)返回到內核態。繼續第五步。 三、可重入函數 信號處理函數的棧幀是私有的。 信號處理函數和進程的執行是異步的。 如果這兩條執行路線出現對共享資源的競爭,這事就大了。 盡量避免競爭。 使我的函數盡量不去訪問棧幀以外的資源。 如果函數中使用了全局變量、靜態的局部變量、malloc的內存。那麽這個函數就是不可重入函數。 可重入函數只能訪問棧幀裏的內容。如果這個函數只有地洞局部變量,那麽這個函數就是可重入函數。 舉例說明 信號處理函數和進程競爭共享資源。 代碼參見 count.c 四、作業 進程組 有一個或多個進程 父進程 子進程 孫子進程 作業分為前臺作業和後臺作業,前臺作業只有一個,後臺作業有多個。 按鍵產生的信號只能發送給前臺作業。 將前臺作業轉換為後臺作業 ctrl
+z 後臺作業轉換為前臺作業 fg %作業號 在後臺運行作業 bg %作業號 查看後臺作業 jobs 在作業啟動的時候,直接將作業放到後臺執行 作業& 補充一句: 子進程結束的時候,子進程向父進程發送SIGCHLD信號,父進程收到,就去收屍。 五、使用setitimer(2)設置計時器 系統計時器做了解 系統運行一個進程時候,進程消耗的時間包含三部分 用戶時間 進程消耗在用戶態的時間 內核時間 進程消耗在內核態的時間 睡眠時間 進程消耗在等待I/O、睡眠等不被調度的時間 內核為系統中的每個進程維護三個計時器 真實計時器 統計進程的執行時間 虛擬計時器 統計進程的用戶時間 實用計時器 統計進程的用戶時間和內核時間 這三個計時器除了統計功能以外,還可以按照自己的規則,以定時器的方式工作,向進程周期性的發送信號。 利用這個功能設計一個計時器 setitimer(
2) #include <sys/time.h> int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value); 功能:設置定時器的間隔值 參數: which: ITIMER_REAL: ITIMER_VIRTUAL: ITIMER_PROF: new_value:指定了定時器的新值 old_value:保存了定時器的舊值 返回值: 0 成功 -1 錯誤 errno被設置 ITIMER_REAL:真實 SIGALRM ITIMER_VIRTUAL:虛擬 SIGVTALRM ITIMER_PROF:實用 SIGPROF struct itimerval{ struct timeval it_interval; /* next value */ struct timeval it_value; /* current value */ }; struct timeval{ long tv_sec; /* seconds */ long tv_usec; /* microseconds */ }; 秒 微秒 1秒=1000毫秒 1毫秒=1000微秒 舉例說明 編寫代碼實現定時器,起始時間是進程啟動3秒,然後每隔0.5秒發送一個SIGALRM信號。 代碼參見 timer.c 信號結束了 六、system v IPC 消息隊列 共享內存 信號量集 在內核管理的內存,用於進程間通訊的內存,稱為system v ipc object 操作系統需要管理這些對象。 如何查看當前系統裏有哪些對象? ipcs 在操作系統中這些對象,每一個都有自己的id。便於操作系統的管理。 在用戶態需要獲取這些對象的id。 獲取這些對象的id。需要在用戶態有一個鍵值(唯一的) 將鍵值和id綁定,這樣就可以獲取到對象的id。 如何獲取這個鍵值? ftok(3) #include <sys/types.h> #include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id); 功能:獲取system v ipc的一個鍵值 key 參數: pathname:指定一個文件名,這個文件是存在的,可訪問的 proj_id:必須是非0.取這個數的有效低8位。 返回值: -1 錯誤 errno被設置 返回一個key值。 舉例說明 使用ftok(3)獲取一個鍵值 代碼參見ftok.c 消息隊列 從系統中獲取一個消息隊列。如果系統裏沒有,創建消息隊列,將這個消息隊列的id給我返回。如果有這個消息隊列,返回id即可。 msgget(2) #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflg); 功能:獲取一個消息隊列的id 參數: key:ftok(3)的返回值 msgflg: IPC_CREAT:如果不存在創建,存在,不創建 IPC_EXCL:如果和IPC_CREAT一起指定,存在的時候,報錯。 mode:指定了消息隊列的權限 返回值: -1 錯誤 errno被設置 返回消息隊列的id 舉例說明 使用msgget(2)從內核獲取消息隊列 代碼參見msgget.c 向消息隊列中發送消息和從消息隊列獲取消息 msgsnd(2) #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 功能:向消息隊列發送消息 參數: msqid:指定了存放消息的消息隊列的id。 msgp:指向了消息的地址 msgsz:指定了消息內容的長度 msgflg: IPC_NOWAIT:非阻塞 0 阻塞 返回值: 成功 0 -1 失敗 errno被設置 將一份拷貝追加到消息隊列中 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg); 功能:從消息隊列接收消息 參數: msqid:指定了消息隊列的id msgp:指向了消息的地址 msgsz:指定了消息內容的長度 msgtyp:指定了消息的類型 msgflg: IPC_NOWAIT:沒有消息的時候,立即返回錯誤 errno被設置 0 沒有消息的時候,阻塞等待 返回值: -1 失敗 errno被設置 成功 返回實際拷貝到mtext中的字節數。 需要用戶自定義這個類型 struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1]; /* message data */ }; typedef struct msgbuf msgb_t; msgb_t *st=malloc(sizeof(msgb_t)+strlen(mtext)-3); st->mtext 舉例說明 兩個進程通過消息隊列實現進程間的通訊。 代碼參見 send.c recv.c 總結: 一、pause(2)函數的使用 二、信號從產生到處理的整個過程 三、可重入函數 四、作業 前臺作業和後臺作業 五、使用setitimer(2)實現定時器 六、進程間通訊 system v ipc 消息隊列

pause、jobs、setitimer(2)、system v ipc(day12)