并发的实现理论基础
1.?? ?linux多任務(wù)編程
?? ?(1)?? ?指用戶可以同一時(shí)間運(yùn)行多個(gè)應(yīng)用程序(任務(wù))。
?? ??? ?windows--->任務(wù)管理器
?? ??? ?linux--->ps -ef
?? ??? ?int main()
?? ??? ?{
?? ??? ??? ?int a = 5,b = 6;
?? ??? ??? ?int sum = a + b;
?? ??? ??? ?printf("sum = %d\n",a + b);
?? ??? ?}
?? ??? ?程序 = 指令 + 數(shù)據(jù);
?? ??? ?用來表示人們思維對(duì)象的抽象概念的物理表現(xiàn)叫做數(shù)據(jù),如a,b
?? ??? ?我們把數(shù)據(jù)處理的規(guī)則叫做操作(指令),如+
?? ??? ?對(duì)某一個(gè)有限數(shù)據(jù)集合所施行的、目的在于解決某一問題的一組有限的指令的集合,稱之為
?? ??? ?一個(gè)計(jì)算(compute).
?? ??? ?計(jì)算機(jī)就是用指令來處理數(shù)據(jù)。所以我們可以稱:
?? ??? ??? ?程序是存放在磁盤上的可執(zhí)行文件,是數(shù)據(jù)和指令的集合,一個(gè)程序的執(zhí)行過程就是一個(gè)計(jì)算。
?? ?(2)?? ?一個(gè)任務(wù)可以包含一個(gè)或多個(gè)獨(dú)立功能的子任務(wù)。
?? ??? ?這里獨(dú)立功能的子任務(wù)稱之為進(jìn)程或線程。如:殺毒軟件....
?? ??? ?進(jìn)程線程他們最主要的目的就是為了實(shí)現(xiàn)并發(fā)。
?? ??? ?現(xiàn)代操作系統(tǒng)為了提高CPU的利用率,特定的引入了并發(fā)的概念。
2.?? ?進(jìn)程
?? ?進(jìn)程是具有獨(dú)立功能的程序在某一個(gè)數(shù)據(jù)集合上的一次動(dòng)態(tài)的執(zhí)行過程。
?? ?簡單的來說,進(jìn)程就是一個(gè)程序的一次執(zhí)行過程,程序一旦執(zhí)行,就變成了進(jìn)程。
?? ?在Linux系統(tǒng)中用task_struct來描述和記錄進(jìn)程的一切,這個(gè)結(jié)構(gòu)體我們也稱之為叫進(jìn)程控制塊
?? ?(Process Control Block)。
?? ??? ?定義在(637行的位置):
?? ??? ??? ?/usr/src/linux-headers-5.3.0-40/include/linux/sched.head
?? ?小結(jié):
?? ?當(dāng)一個(gè)程序執(zhí)行時(shí),系統(tǒng)就會(huì)創(chuàng)建/啟動(dòng)一個(gè)進(jìn)程,這個(gè)進(jìn)程用結(jié)構(gòu)體來描述,其中記錄和描述了
?? ?這個(gè)進(jìn)程所需要的所有資源,隨著這個(gè)進(jìn)程的運(yùn)行,各種資源被分配和釋放,是一個(gè)動(dòng)態(tài)的過程。
3.?? ?進(jìn)程的組織形式
?? ?在系統(tǒng)中每一個(gè)進(jìn)程都有一個(gè)唯一的ID,稱之為PID。
?? ?PID是重要的系統(tǒng)資源,是區(qū)分其他進(jìn)程的基本依據(jù)。其本質(zhì)上是一個(gè)整數(shù)(>=0).
?? ?在主流的操作系統(tǒng)中,如果進(jìn)程A啟動(dòng)了進(jìn)程B,把進(jìn)程A稱之為進(jìn)程B的父進(jìn)程,進(jìn)程B稱之為
?? ?進(jìn)程A的子進(jìn)程。
?? ?linux中任何一個(gè)進(jìn)程都有一個(gè)創(chuàng)建/啟動(dòng)它的“父母”。
?? ?linux中進(jìn)程0啟動(dòng)了進(jìn)程1和進(jìn)程2,其他進(jìn)程都是由進(jìn)程1或進(jìn)程2創(chuàng)建/啟動(dòng)的,從而形成了樹狀結(jié)構(gòu)。
4.?? ?進(jìn)程狀態(tài)
?? ?在單CPU的計(jì)算機(jī)中,所謂"同時(shí)"運(yùn)行多個(gè)任務(wù)(并發(fā)),并不是真正的同時(shí),系統(tǒng)把CPU的執(zhí)行時(shí)間
?? ?切分為細(xì)小的單位,如10ms,稱之為時(shí)間片,在單個(gè)時(shí)間片執(zhí)行一個(gè)程序,時(shí)間片到,就執(zhí)行
?? ?下一個(gè)程序,如此循環(huán)。
?? ?進(jìn)程是程序的執(zhí)行過程,有自己的生命周期,可分為如下狀態(tài):
?? ??? ?就緒態(tài):進(jìn)程具備執(zhí)行的一切條件,正在等待CPU的資源
?? ??? ?運(yùn)行態(tài):進(jìn)程正在運(yùn)行,占用CPU
?? ??? ?阻塞態(tài):因等待某一個(gè)事件發(fā)生而休眠,如果等待的資源分配到,就會(huì)被喚醒進(jìn)入就緒態(tài)。
?? ?所有就緒的進(jìn)程會(huì)組成一個(gè)“就緒隊(duì)列”:Ready Queue
?? ?那么我們會(huì)有一個(gè)“調(diào)度程序”負(fù)責(zé)確定下一個(gè)進(jìn)入"Running"狀態(tài)的進(jìn)程。
?? ?“調(diào)度程序”是按某種“調(diào)度策略(調(diào)度算法)”來進(jìn)行調(diào)度的,如:
?? ??? ?分時(shí)系統(tǒng):
?? ??? ??? ?調(diào)度策略以“時(shí)間片輪轉(zhuǎn)”為主要策略的系統(tǒng)
?? ??? ??? ?“時(shí)間片輪轉(zhuǎn)”:分時(shí),每一個(gè)進(jìn)程執(zhí)行一段時(shí)間(“時(shí)間片”)。
?? ??? ??? ?如:大部分的桌面系統(tǒng) Linux Android windows unix...
?? ??? ?實(shí)時(shí)系統(tǒng):
?? ??? ??? ?調(diào)度策略以“實(shí)時(shí)策略”為主要策略的系統(tǒng)
?? ??? ??? ?“實(shí)時(shí)策略”:每次調(diào)度都取優(yōu)先級(jí)最高的那個(gè)進(jìn)程執(zhí)行,直到這個(gè)進(jìn)程執(zhí)行完畢,或者
?? ??? ??? ?它主動(dòng)放棄CPU或更高優(yōu)先級(jí)的進(jìn)程搶占。
?? ??? ??? ?如:UCOS,freeRTOS...
?? ??? ?無論是哪種系統(tǒng)都會(huì)有“搶占(插隊(duì))”的情況發(fā)生。
5.?? ?linux進(jìn)程地址空間布局
?? ?進(jìn)程一旦誕生,第一件事情就是申請(qǐng)一塊內(nèi)存區(qū)域來存儲(chǔ)程序的“數(shù)據(jù)”。
?? ?那么一個(gè)程序里面“數(shù)據(jù)”的屬性是不一致的,所以我們需要分區(qū)域來存儲(chǔ)程序的數(shù)據(jù)。
?? ?linux對(duì)進(jìn)程的數(shù)據(jù)進(jìn)行分段處理,不同的屬性的數(shù)據(jù)存儲(chǔ)在不同的“內(nèi)存段”,不同的“內(nèi)存段”
?? ?的屬性和管理方式是不一致的。
?? ?在32位的操作系統(tǒng)中,任何一個(gè)進(jìn)程的誕生,操作系統(tǒng)都會(huì)為其分配一塊4G的虛擬內(nèi)存空間。
?? ?.text段:
?? ??? ?主要存放代碼。
?? ??? ?只讀并且共享的。
?? ??? ?這段內(nèi)存在程序的運(yùn)行期間(進(jìn)程的存活期間),不會(huì)釋放的。
?? ??? ?“代碼段”隨程序持續(xù)性(隨進(jìn)程的持續(xù)性)。
?? ?.rodata只讀數(shù)據(jù)段。
?? ??? ?主要存放程序中的只讀數(shù)據(jù)。
?? ??? ?比如:字符串.....
?? ??? ?只讀,這段內(nèi)存在進(jìn)程的運(yùn)行期間,一直存在。隨進(jìn)程的持續(xù)性。
?? ?.data數(shù)據(jù)段:
?? ??? ?主要存放程序已經(jīng)初始化的全局變量和已經(jīng)初始化的static變量。
?? ??? ?可讀可寫的。這段內(nèi)存在進(jìn)程運(yùn)行期間,一直存在。隨進(jìn)程持續(xù)性。
?? ?.bss數(shù)據(jù)段:
?? ??? ?主要存放程序的沒有初始化的全局變量和沒有初始化的static變量。
?? ??? ?可讀可寫的。這段內(nèi)存在進(jìn)程運(yùn)行期間,一直存在。隨進(jìn)程持續(xù)性。
?? ??? ?.bss段,在進(jìn)程初始化時(shí),(可能)全部初始化為0.
?? ?.heap(堆空間):
?? ??? ?動(dòng)態(tài)內(nèi)存空間
?? ??? ?主要是由malloc/realloc/calloc動(dòng)態(tài)分配的空間。
?? ??? ?可讀可寫的。這段內(nèi)存在進(jìn)程運(yùn)行期間,一旦分配,就會(huì)一直存在,直到你手動(dòng)free或者進(jìn)程消亡。
?? ??? ?防止“內(nèi)存泄露/垃圾內(nèi)存”。
?? ?.stack(棧空間)
?? ??? ?主要存放局部變量(非static的局部變量)
?? ??? ?可讀可寫,這段空間,會(huì)自動(dòng)釋放(代碼塊執(zhí)行完畢了,代碼塊中間的局部變量的空間就會(huì)自動(dòng)釋放)
?? ??? ?隨代碼塊的持續(xù)性。
?? ?新名詞:
?? ??? ?用戶態(tài) 內(nèi)核態(tài) 特權(quán)級(jí) 虛擬地址空間
6.?? ?Linux下進(jìn)程相關(guān)的API函數(shù)
?? ?1)?? ?創(chuàng)建進(jìn)程
?? ??? ?NAME
?? ??? ??? ?fork - create a child process
?? ??? ?SYNOPSIS
?? ??? ??? ?#include <sys/types.h>
?? ??? ??? ?#include <unistd.h>
?? ??? ??? ?pid_t fork(void);
?? ??? ??? ?通過復(fù)制調(diào)用進(jìn)程來創(chuàng)建新的子進(jìn)程,新的進(jìn)程幾乎和原有進(jìn)程一樣,但他有自己的PID。
?? ??? ??? ?返回值:
?? ??? ??? ??? ?當(dāng)fork調(diào)用成功,就創(chuàng)建出一個(gè)新的進(jìn)程。
?? ??? ??? ??? ?把新進(jìn)程的PID返回給父進(jìn)程,進(jìn)程自己本身就返回0.
?? ??? ??? ??? ?如果fork失敗,返回-1,可以使用perror獲取錯(cuò)誤原因。
?? ??? ?注意:
?? ??? ??? ?1.?? ?當(dāng)創(chuàng)建子進(jìn)程后,那么父進(jìn)程和子進(jìn)程到底誰先執(zhí)行,不一定。
?? ??? ??? ?2.?? ?如果父進(jìn)程先執(zhí)行,執(zhí)行完成后,子進(jìn)程還沒有結(jié)束,那么子進(jìn)程會(huì)認(rèn)其他進(jìn)程
?? ??? ??? ??? ?為新的父進(jìn)程。
?? ??? ??? ?3.?? ?新的進(jìn)程是復(fù)制創(chuàng)建出來的,擁有父進(jìn)程所有的資源。新的進(jìn)程從fork之后開始執(zhí)行。
?? ??? ??? ??? ?即fork之前的代碼父進(jìn)程執(zhí)行一次,fork之后的代碼,父子進(jìn)程同時(shí)執(zhí)行。
?? ??? ?思考題:
?? ??? ??? ?寫一個(gè)代碼,創(chuàng)建4個(gè)進(jìn)程。
?? ??? ??? ?int main()
?? ??? ??? ?{
?? ??? ??? ??? ?fork();
?? ??? ??? ??? ?fork();
?? ??? ??? ??? ?printf("Hello,Process!\n");
?? ??? ??? ?}
?? ?2)?? ?獲取PID
?? ??? ?NAME
?? ??? ??? ?getpid, getppid - get process identification
?? ??? ?SYNOPSIS
?? ??? ??? ?#include <sys/types.h>
?? ??? ??? ?#include <unistd.h>
?? ??? ??? ?pid_t getpid(void);
?? ??? ??? ?獲取當(dāng)前進(jìn)程的ID
?? ??? ??? ?pid_t getppid(void);
?? ??? ??? ?獲取當(dāng)前進(jìn)程的父進(jìn)程的ID
?? ??? ?思考題:
?? ??? ??? ?int main()
?? ??? ??? ?{
?? ??? ??? ??? ?fork();
?? ??? ??? ??? ?fork() && fork() || fork(); ?((1) && (2)) || (3)
?? ??? ??? ??? ?fork();
?? ??? ??? ??? ?printf("Hello!\n");
?? ??? ??? ?}
?? ?(3)?? ?進(jìn)程退出
?? ??? ?3.1?? ?正常退出(自殺)
?? ??? ??? ?a.?? ?在main函數(shù)中執(zhí)行return xxx;
?? ??? ??? ?b.?? ?調(diào)用exit/_exit函數(shù)
?? ??? ??? ??? ?NAME
?? ??? ??? ??? ??? ?_exit - terminate the calling process
?? ??? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ??? ?#include <unistd.h>
?? ??? ??? ??? ??? ?void _exit(int status);
?? ??? ??? ??? ??? ??? ?status:表示的是退出碼,表示退出狀態(tài)。
?? ??? ??? ??? ??? ??? ?退出碼的具體含義,由程序猿自己來決定。
?? ??? ??? ??? ??? ??? ?坐火箭連夜走的,不會(huì)做清理工作。
?? ??? ??? ??? ?NAME
?? ??? ??? ??? ??? ?exit - cause normal process termination
?? ??? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ??? ?#include <stdlib.h>
?? ??? ??? ??? ??? ?void exit(int status);
?? ??? ??? ??? ??? ??? ?status:表示的是退出碼,表示退出狀態(tài)。
?? ??? ??? ??? ??? ??? ?退出碼的具體含義,由程序猿自己來決定。
?? ??? ??? ??? ??? ??? ?exit正常退出,會(huì)做一些清理工作(如:清理緩沖區(qū))。
?? ??? ?3.2?? ?非正常退出(他殺)
?? ??? ??? ?在外力干涉下結(jié)束。
?? ??? ??? ?如進(jìn)程出現(xiàn)段錯(cuò)誤,系統(tǒng)會(huì)自動(dòng)干掉進(jìn)程。
?? ?(4)?? ?注冊(cè)終止函數(shù)
?? ??? ?即main函數(shù)正常結(jié)束后調(diào)用的函數(shù)。
?? ??? ?NAME
?? ??? ??? ?atexit - register a function to be called at normal process termination
?? ??? ?SYNOPSIS
?? ??? ??? ?#include <stdlib.h>
?? ??? ??? ?int atexit(void (*function)(void));
?? ??? ??? ??? ?void (*function)(void)---> 函數(shù)指針
?? ??? ??? ??? ?void *function(void) ?---> 指針函數(shù)
?? ??? ?注意:
?? ??? ??? ?1.?? ?atexit()注冊(cè)的函數(shù)類型應(yīng)為不接受任何參數(shù)的void函數(shù)。
?? ??? ??? ?2.?? ?調(diào)用注冊(cè)函數(shù)的順序與他們注冊(cè)時(shí)候的順序是相反的。
?? ??? ??? ??? ?同一個(gè)函數(shù)若注冊(cè)多次,則也會(huì)被調(diào)用多次。
?? ??? ??? ?3.?? ?如果main函數(shù)是非正常退出的情況下,注冊(cè)函數(shù)將不會(huì)被調(diào)用。
?? ?(5)?? ?等待進(jìn)程
?? ??? ?NAME
?? ??? ??? ?wait, waitpid - wait for process to change state
?? ??? ?SYNOPSIS
?? ??? ??? ?#include <sys/types.h>
?? ??? ??? ?#include <sys/wait.h>
?? ??? ??? ?pid_t wait(int *wstatus);
?? ??? ??? ?pid_t waitpid(pid_t pid, int *wstatus, int options);
?? ??? ??? ?一個(gè)進(jìn)程退出,操作系統(tǒng)會(huì)釋放這個(gè)退出進(jìn)程的大部分資源,但是有一部分必須留給他的
?? ??? ??? ?父進(jìn)程去釋放。如果一個(gè)進(jìn)程退出了,但是它父進(jìn)程沒有去釋放這個(gè)進(jìn)程,那么這個(gè)進(jìn)程
?? ??? ??? ?就會(huì)變成僵尸進(jìn)程。
?? ??? ??? ?僵尸進(jìn)程:進(jìn)程已經(jīng)死掉了但是資源沒有被完全釋放掉(還沒死透)。
?? ??? ??? ?這兩個(gè)函數(shù)的作用是用來等待某個(gè)(某些)子進(jìn)程退出的,當(dāng)子進(jìn)程正常退出時(shí),調(diào)用
?? ??? ??? ?wait/waitpid可以釋放子進(jìn)程的資源,假如沒有調(diào)用,那么子進(jìn)程退出后,就會(huì)變成僵尸進(jìn)程。
?? ??? ??? ?查看進(jìn)程的狀態(tài):ps -aux/ps -ef
?? ??? ??? ?pid_t wait(int *wstatus);
?? ??? ??? ?父進(jìn)程一旦調(diào)用wait,就立即阻塞自己,由wait自動(dòng)分析當(dāng)前進(jìn)程的某個(gè)子進(jìn)程是否退出。
?? ??? ??? ?如果讓它找到一個(gè)已經(jīng)變成僵尸進(jìn)程的子進(jìn)程,wait就會(huì)收集這個(gè)子進(jìn)程的信息,并將子進(jìn)程
?? ??? ??? ?銷毀后返回。如果沒有找到這樣的一個(gè)子進(jìn)程,wait就會(huì)一直阻塞,直到有一個(gè)符合條件的
?? ??? ??? ?進(jìn)程出現(xiàn)為止。
?? ??? ??? ?其中有一個(gè)參數(shù),status:它是一個(gè)指針,那么這個(gè)參數(shù)是用來收集子進(jìn)程的退出信息的,
?? ??? ??? ?所以它指向的空間用來保存子進(jìn)程的退出信息的(子進(jìn)程是正常退出的還是非正常退出的、
?? ??? ??? ?退出碼以及被誰殺死等)。如果我們并不在意子進(jìn)程的退出信息的話,那么我們就可以設(shè)定
?? ??? ??? ?這個(gè)參數(shù)為NULL。
?? ??? ??? ?返回值:成功返回退出的那個(gè)子進(jìn)程的進(jìn)程ID,失敗返回-1,同時(shí)errno被設(shè)置。
?? ??? ??? ?需要的注意:
?? ??? ??? ??? ?status是一個(gè)整數(shù),這個(gè)空間內(nèi)用來保存退出的子進(jìn)程的退出信息,因?yàn)橥顺鲂畔?br /> ?? ??? ??? ?較多,需要全部保存在一個(gè)32bit的空間內(nèi)的話,就必須要分段進(jìn)行保存。
?? ??? ??? ??? ?比如:我們的退出碼就保存在第8bit到第15bit的段中。
?? ??? ??? ??? ?子進(jìn)程 -->?? ?exit(123)
?? ??? ??? ??? ?父進(jìn)程 --> ?wait(&status)
?? ??? ??? ??? ?如果我們要獲取到進(jìn)程的退出信息的話則必須要對(duì)status進(jìn)行解析,解析通過如下的宏:
?? ??? ??? ??? ??? ?WIFEXITED(status)
?? ??? ??? ??? ??? ?如果子進(jìn)程是正常退出的話,將會(huì)返回一個(gè)非零值。
?? ??? ??? ??? ??? ?WEXITSTATUS(status)
?? ??? ??? ??? ??? ?當(dāng)WIFEXITED返回一個(gè)非零值時(shí),我們就可以用這個(gè)宏來提取子進(jìn)程的退出碼(返回值)
?? ??? ??? ??? ??? ?如果子進(jìn)程調(diào)用 exit(4) ?那么WEXITSTATUS(status)-->4
?? ??? ??? ??? ??? ??? ??? ??? ? ? exit(257) ? ?WEXITSTATUS(status)-->1
?? ??? ??? ??? ??? ?如果WIFEXITED返回的是一個(gè)0,那么WEXITSTATUS則沒有任何意義。
?? ??? ??? ?pid_t waitpid(pid_t pid, int *wstatus, int options);
?? ??? ??? ??? ?pid:指定要等待的進(jìn)程或進(jìn)程組
?? ??? ??? ??? ??? ?pid == -1?? ?表示等待任意的子進(jìn)程退出
?? ??? ??? ??? ??? ?pid == 0 ? ?表示等待的與調(diào)用進(jìn)程同組的任意子進(jìn)程
?? ??? ??? ??? ??? ??? ??? ??? ?“進(jìn)程組”:就是一組進(jìn)程。
?? ??? ??? ??? ??? ??? ??? ??? ?每一個(gè)進(jìn)程必須會(huì)屬于某一個(gè)進(jìn)程組,并且每個(gè)進(jìn)程組,都會(huì)有一個(gè)
?? ??? ??? ??? ??? ??? ??? ??? ?組長進(jìn)程,一般來說,創(chuàng)建這個(gè)進(jìn)程組的進(jìn)程為組長,進(jìn)程組有一個(gè)
?? ??? ??? ??? ??? ??? ??? ??? ?組ID,這個(gè)組ID,就是組長進(jìn)程的ID。
?? ??? ??? ??? ??? ?pid < -1?? ?表示等待組ID等于pid絕對(duì)值的那個(gè)組的任意子進(jìn)程
?? ??? ??? ??? ??? ??? ??? ??? ?如:
?? ??? ??? ??? ??? ??? ??? ??? ??? ?pid == -2398
?? ??? ??? ??? ??? ??? ??? ??? ??? ?等待進(jìn)程組id為2398那個(gè)組內(nèi)的任意的子進(jìn)程
?? ??? ??? ??? ??? ?pid > 0?? ??? ?表示等待指定的子進(jìn)程(其進(jìn)程ID為pid的那個(gè)子進(jìn)程)
?? ??? ??? ??? ?wstatus:同上
?? ??? ??? ??? ?options:等待選項(xiàng)。
?? ??? ??? ??? ??? ?0 ?? ? ? ? ?? ?表示阻塞等待
?? ??? ??? ??? ??? ?WNOHANG ?? ?表示非阻塞,假如沒有子進(jìn)程退出,則立即返回。
?? ??? ??? ??? ?返回值:
?? ??? ??? ??? ??? ?成功返回退出的那個(gè)子進(jìn)程的進(jìn)程ID,失敗返回-1,同時(shí)errno被設(shè)置。
?? ??? ??? ??? ??? ?wait(&status) <===> waitpid(-1,&status,0)
?? ?(6)?? ?啟動(dòng)外部程序
?? ??? ?NAME
?? ??? ??? ?execl, execlp, execle, execv, execvp, execvpe - execute a file
?? ??? ?SYNOPSIS
?? ??? ??? ?#include <unistd.h>
?? ??? ??? ?extern char **environ;//char *argv[]
?? ??? ??? ?int execl(const char *path, const char *arg, ...
?? ??? ??? ??? ??? ??? ? ? /* (char ?*) NULL */);
?? ??? ??? ?int execlp(const char *file, const char *arg, ...
?? ??? ??? ??? ??? ??? ? ? /* (char ?*) NULL */);
?? ??? ??? ?int execle(const char *path, const char *arg, ...
?? ??? ??? ??? ??? ??? ? ? /*, (char *) NULL, char * const envp[] */);
?? ??? ??? ?int execv(const char *path, char *const argv[]);
?? ??? ??? ?int execvp(const char *file, char *const argv[]);
?? ??? ??? ?int execvpe(const char *file, char *const argv[],
?? ??? ??? ??? ??? ??? ? ? char *const envp[]);
?? ??? ??? ?exec函數(shù)族是讓一個(gè)進(jìn)程去執(zhí)行另外一個(gè)程序文件。
?? ??? ?(1)?? ?int execl(const char *path, const char *arg, .../* (char ?*) NULL */);
?? ??? ??? ?讓進(jìn)程去執(zhí)行參數(shù)指定的程序文件
?? ??? ??? ?參數(shù):
?? ??? ??? ??? ?path:程序文件的文件名(需要帶路徑)
?? ??? ??? ??? ?arg, ...:新程序執(zhí)行需要的參數(shù),參數(shù)個(gè)數(shù)可變
?? ??? ??? ??? ??? ?如:
?? ??? ??? ??? ??? ??? ?"sum","3","5",NULL
?? ??? ??? ??? ??? ?注意:參數(shù)的個(gè)數(shù)可以很多,但最后要以NULL作為結(jié)尾表示參數(shù)輸入結(jié)束。
?? ??? ??? ??? ??? ??? ? 參數(shù)列表中的第一個(gè)參數(shù)應(yīng)該要是程序的名字。
?? ??? ??? ?帶l的意思就是參數(shù)是以列表的形式存在的。
?? ??? ??? ?返回值:
?? ??? ??? ??? ?出錯(cuò)返回-1,成功不會(huì)返回。
?? ??? ?(2)?? ?int execv(const char *path, char *const argv[]);
?? ??? ??? ?execv和execl作用、功能、返回值都是一樣的。
?? ??? ??? ?唯一的區(qū)別在于,指定的程序文件的參數(shù)不一樣。
?? ??? ??? ??? ?path:程序文件的文件名(需要帶路徑)
?? ??? ??? ??? ?argv:指定程序運(yùn)行的參數(shù)。程序運(yùn)行的第一個(gè)參數(shù)是程序名,最后一個(gè)為NULL。
?? ??? ??? ?帶v的意思就是參數(shù)以數(shù)組的形式存在。
?? ??? ?(3)?? ?int execlp(const char *file, const char *arg, .../* (char ?*) NULL */);
?? ??? ??? ?int execvp(const char *file, char *const argv[]);
?? ??? ??? ?帶p(PATH):意思就是指定的程序文件在標(biāo)準(zhǔn)的命令的搜索路徑(PATH)下
?? ??? ??? ?參數(shù):file:要執(zhí)行的程序的文件名(可以不帶路徑)
?? ??? ??? ??? ?其他參數(shù)同上。
?? ??? ?(4)?? ?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(enviroment):使用環(huán)境變量數(shù)組設(shè)置新執(zhí)行的程序運(yùn)行的環(huán)境,不使用進(jìn)程原有的環(huán)境變量
?? ??? ??? ?環(huán)境變量:環(huán)境變量中包含了用戶的主目錄,命令的搜索路徑、當(dāng)前目錄等等。
?? ??? ??? ?他們包含了用戶的工作環(huán)境,所以稱之為環(huán)境變量。
?? ?(7)?? ?system
?? ??? ?NAME
?? ??? ??? ?system - execute a shell command
?? ??? ?SYNOPSIS
?? ??? ??? ?#include <stdlib.h>
?? ??? ??? ?int system(const char *command);
?? ??? ??? ?system用來執(zhí)行command指定的命令或程序或shell腳本。
?? ??? ??? ?system會(huì)等待命令或程序執(zhí)行完畢,system實(shí)際上是新創(chuàng)建了一個(gè)進(jìn)程去執(zhí)行指定的命令或
?? ??? ??? ?程序。
?? ??? ??? ?返回值:成功返回狀態(tài)碼,失敗返回-1.
?? ??? ??? ?sudo apt-get install mplayer
?? ??? ??? ?mplayer
?? ?作業(yè):
?? ??? ?寫一個(gè)程序,創(chuàng)建一個(gè)子進(jìn)程,播放一個(gè)目錄中的MP3/MP4文件,實(shí)現(xiàn)自動(dòng)循環(huán)播放。
?? ??? ?//搜索所有的MP3/MP4文件-->鏈表
?? ??? ?while(1)
?? ??? ?{
?? ??? ??? ?//取下一首歌
?? ??? ??? ?pid_t pid = fork();
?? ??? ??? ?if(兒子)
?? ??? ??? ?{
?? ??? ??? ??? ?exec-->讓兒子去播放MP3
?? ??? ??? ?}
?? ??? ??? ?else//老子
?? ??? ??? ?{
?? ??? ??? ??? ?wait 兒子
?? ??? ??? ?}
?? ??? ?}
7.?? ?IPC:Internal Processes Communication
?? ?進(jìn)程間通信,實(shí)質(zhì):信息(數(shù)據(jù))的交換。
?? ?如果兩個(gè)進(jìn)程要進(jìn)行通信,必須要把數(shù)據(jù)放在一個(gè)大家都能夠訪問到的地方。
?? ?文件可以嗎?當(dāng)然可以。
?? ?這種方式有一個(gè)缺點(diǎn):速度太慢了。
?? ?IPC手段:
?? ??? ?管道:?? ?pipe?? ?無名管道
?? ??? ??? ??? ?fifo ?? ?有名管道
?? ??? ?信號(hào):?? ?signal
?? ??? ?消息隊(duì)列:Message
?? ??? ??? ??? ?System V消息隊(duì)列/POSIX消息隊(duì)列
?? ??? ?信號(hào)量:System V信號(hào)量/POSIX信號(hào)量
?? ??? ?共享內(nèi)存:System V共享內(nèi)存/POSIX共享內(nèi)存
?? ??? ?Socket通信:套接字
?? ?a long long ago,其實(shí)進(jìn)程間通信都是通過文件的。
?? ?缺點(diǎn)->效率太低,速度太慢
?? ?優(yōu)點(diǎn)->簡單,不需要額外的提供其他的API函數(shù)(open/read/write)
?? ?文件內(nèi)容是在外設(shè)(硬盤)上,文件系統(tǒng)中。
?? ?能不能把文件的內(nèi)容放到內(nèi)核或內(nèi)存中去呢?
?? ?管道:管道文件,但是內(nèi)容是在內(nèi)存或內(nèi)核中。
?? ?(1)?? ?無名管道 pipe
?? ??? ?我們說管道雖然是一個(gè)文件,但是它在文件系統(tǒng)中沒有名字(沒有inode),它的內(nèi)容是內(nèi)存中,
?? ??? ?訪問pipe的方式還是通過文件系統(tǒng)的API函數(shù)(open/read/write).
?? ??? ?但是它又不能用open(因?yàn)闆]有名字),問題是read/write必須要先open才能通過文件描述符
?? ??? ?進(jìn)行操作。所以在創(chuàng)建這個(gè)pipe的時(shí)候,就必須要返回文件描述符。
?? ??? ?pipe在創(chuàng)建時(shí),在內(nèi)核中開辟一塊緩沖區(qū),作為pipe文件內(nèi)容的存儲(chǔ)空間,同時(shí)返回兩個(gè)文件描述符
?? ??? ?(一個(gè)用來讀,一個(gè)用來寫)
?? ??? ?注意:
?? ??? ??? ?1.?? ?pipe有兩端,一端是用來寫的,一端是用來讀的。
?? ??? ??? ?2.?? ?按順序讀,不能lseek。
?? ??? ??? ?3.?? ?內(nèi)容讀走了,就沒有啦!
?? ??? ??? ?4.?? ?pipe(無名管道)隨內(nèi)核的持續(xù)性。
?? ??? ?NAME
?? ??? ??? ?pipe - create pipe
?? ??? ?SYNOPSIS
?? ??? ??? ?#include <unistd.h>
?? ??? ??? ?int pipe(int pipefd[2]);
?? ??? ??? ?pipe用來在內(nèi)核中創(chuàng)建一個(gè)無名管道。
?? ??? ??? ?pipefd用來保存創(chuàng)建好的無名管道的兩個(gè)文件描述符。
?? ??? ??? ?pipefd:數(shù)組
?? ??? ??? ??? ?pipefd[0]?? ?保存讀的文件描述符
?? ??? ??? ??? ?pipefd[1]?? ?保存寫的文件描述符
?? ??? ??? ?返回值:成功返回0,失敗返回-1,同時(shí)errno被設(shè)置。
?? ??? ??? ?無名管道的通信方式是阻塞的,當(dāng)管道中沒有東西可以讀時(shí),那么阻塞,直到管道中有
?? ??? ??? ?東西可以讀。當(dāng)管道中不能寫的時(shí)候,那么阻塞,直到管道中有空間繼續(xù)寫為止。
?? ??? ?注意:
?? ??? ??? ?1.?? ?原則上來講,只要兩個(gè)進(jìn)程能夠獲取到同一個(gè)pipe的文件描述符,就可以用pipe來
?? ??? ??? ?通信。管道一般我們是用于有親緣關(guān)系的進(jìn)程之間通信。
?? ??? ??? ?2.?? ?pipe本身是一個(gè)全雙工的通信,但是兩個(gè)進(jìn)程用一個(gè)管道去實(shí)現(xiàn)全雙工的通信可能會(huì)有
?? ??? ??? ?問題。問題就是自己很有可能讀到自己寫進(jìn)去的數(shù)據(jù)!所以我們認(rèn)為的把pipe當(dāng)成是半雙工
?? ??? ??? ?來使用。
?? ?(2)?? ?有名管道 fifo
?? ??? ?pipe(無名管道)一般用于有親緣關(guān)系的進(jìn)程間通信,-->原因就是pipe沒有名字。
?? ??? ?假設(shè)它如果有名字的話,那么就能夠用于任意進(jìn)程間通信了。那么這個(gè)有名字的管道就是我們的
?? ??? ?有名管道。
?? ??? ?fifo是在pipe的基礎(chǔ)上,給fifo在文件系統(tǒng)中創(chuàng)建一個(gè)inode(在文件系統(tǒng)中有一個(gè)名字),
?? ??? ?但是fifo的文件內(nèi)容同樣的也是出于內(nèi)核或內(nèi)存中。
?? ??? ?fifo的文件內(nèi)容存在于內(nèi)核中,隨內(nèi)核的持續(xù)性。
?? ??? ?fifo的文件名隨文件系統(tǒng)的持續(xù)性。
?? ??? ?那么操作fifo的步驟就是:
?? ??? ??? ?open -> read/write -> close
?? ??? ?創(chuàng)建一個(gè)fifo:
?? ??? ??? ?NAME
?? ??? ??? ??? ?mkfifo - make a FIFO special file (a named pipe)
?? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ?#include <sys/types.h>
?? ??? ??? ??? ?#include <sys/stat.h>
?? ??? ??? ??? ?int mkfifo(const char *pathname, mode_t mode);
?? ??? ??? ??? ?mkfifo用來在文件系統(tǒng)中創(chuàng)建一個(gè)fifo(有名管道)
?? ??? ??? ??? ??? ?pathname:要?jiǎng)?chuàng)建的有名管道在文件系統(tǒng)中名字
?? ??? ??? ??? ??? ?mode:創(chuàng)建的有名管道的權(quán)限,有兩種方式指定:
?? ??? ??? ??? ??? ??? ?a.?? ?S_IRUSR...
?? ??? ??? ??? ??? ??? ?b.?? ?0660...
?? ??? ??? ??? ??? ?函數(shù)返回值:
?? ??? ??? ??? ??? ??? ?成功返回0,失敗返回-1,同時(shí)errno被設(shè)置。
?? ??? ??? ??? ?fifo的創(chuàng)建有兩種不同的形式:
?? ??? ??? ??? ??? ?1.?? ?通過指令 mkfifo
?? ??? ??? ??? ??? ??? ?創(chuàng)建有名管道的時(shí)候,請(qǐng)創(chuàng)建到linux目錄下去,不要?jiǎng)?chuàng)建到共享文件夾內(nèi),
?? ??? ??? ??? ??? ??? ?因?yàn)閣indow不支持fifo。
?? ??? ??? ??? ??? ?2.?? ?通過函數(shù)mkfifo-->請(qǐng)使用絕對(duì)路徑
?? ??? ??? ?A ?FIFO special file (a named pipe) is similar to a pipe, except that it is accessed
?? ??? ??? ?as part of the filesystem. ?It can be opened by multiple processes ?for ?reading ?or
?? ??? ??? ?writing. ? When ?processes ?are ?exchanging data via the FIFO, the kernel passes all
?? ??? ??? ?data internally without writing it to the filesystem. ?Thus, the FIFO ?special ?file
?? ??? ??? ?has no contents on the filesystem; the filesystem entry merely serves as a reference
?? ??? ??? ?point so that processes can access the pipe using a name in the filesystem.
?? ??? ??? ?FIFO(有名管道)和PIPE(無名管道)是類似的,除了它在文件系統(tǒng)中有一個(gè)名字。
?? ??? ??? ?它可以被多個(gè)進(jìn)程打開用來讀或者寫,當(dāng)我們的進(jìn)程用FIFO來交換數(shù)據(jù)的時(shí)候,
?? ??? ??? ?內(nèi)核它根本沒有把數(shù)據(jù)寫入到文件系統(tǒng)中去,而是保存在內(nèi)核的內(nèi)部。
?? ??? ??? ?因此FIFO在文件系統(tǒng)中沒有內(nèi)容,它僅作為文件系統(tǒng)的一個(gè)入口,提供一個(gè)文件名,給
?? ??? ??? ?其他進(jìn)程去open它。
?? ??? ??? ?在數(shù)據(jù)交換前,FIFO的兩端(read,write)必須都被打開。
?? ??? ??? ?通常情況下,你打開FIFO的一端,會(huì)阻塞,直到另外一端也被打開。
?? ??? ??? ?一個(gè)進(jìn)程也可以以“非阻塞”的方式(O_NONBLOCK)去打開管道,在這種情況下,只讀打開
?? ??? ??? ?只總會(huì)成功,即使是寫端還沒有被打開。
?? ??? ??? ?寫打開總會(huì)失敗,并且errno == EENXIO,除非讀端已經(jīng)打開。
?? ?(3)?? ?信號(hào)
?? ??? ?信號(hào)是進(jìn)程間通信的一種方式,這種方式?jīng)]有傳輸數(shù)據(jù),只是在內(nèi)核中傳遞一個(gè)信號(hào),
?? ??? ?信號(hào)其本質(zhì)是一個(gè)整數(shù)。
?? ??? ?不同的信號(hào)值,代表不同的含義,用戶可以自定義信號(hào)。
?? ??? ?那么自定義的信號(hào)的含義和值由程序猿來定義和解釋。
?? ??? ?那么信號(hào)的本質(zhì)也是一個(gè)軟中斷。信號(hào)是異步的。
?? ??? ?信號(hào)會(huì)中斷正在進(jìn)行的程序,轉(zhuǎn)而去處理中斷(處理函數(shù)),處理完中斷后,再回來繼續(xù)執(zhí)行
?? ??? ?原來的程序。
?? ??? ?注意:
?? ??? ??? ?如果用戶沒有顯示的處理信號(hào),系統(tǒng)的默認(rèn)處理方式大多是終止進(jìn)程。
?? ??? ?Signal ? ? Value ? ? Action ? Comment
?? ??? ?──────────────────────────────────────────────────────────────────────
?? ??? ?SIGHUP ? ? ? ?1 ? ? ? Term ? ?Hangup detected on controlling terminal
?? ??? ??? ??? ??? ??? ??? ??? ??? ? ?or death of controlling process
?? ??? ?SIGINT ? ? ? ?2 ? ? ? Term ? ?Interrupt from keyboard
?? ??? ??? ?從鍵盤上獲取信號(hào)2,按下Ctrl + C
?? ??? ?SIGQUIT ? ? ? 3 ? ? ? Core ? ?Quit from keyboard
?? ??? ??? ?默認(rèn)的處理是輸出信息然后終止進(jìn)程,按下Ctrl + /就會(huì)產(chǎn)生這個(gè)信號(hào)
?? ??? ?SIGILL ? ? ? ?4 ? ? ? Core ? ?Illegal Instruction
?? ??? ?SIGABRT ? ? ? 6 ? ? ? Core ? ?Abort signal from abort(3)
?? ??? ?SIGFPE ? ? ? ?8 ? ? ? Core ? ?Floating-point exception
?? ??? ??? ?浮點(diǎn)型異常的時(shí)候,就會(huì)產(chǎn)生這個(gè)信號(hào)
?? ??? ?SIGKILL ? ? ? 9 ? ? ? Term ? ?Kill signal
?? ??? ??? ?殺死進(jìn)程,不可被捕獲和忽略的。
?? ??? ?SIGSEGV ? ? ?11 ? ? ? Core ? ?Invalid memory reference
?? ??? ??? ?非法內(nèi)存引用時(shí),會(huì)收到這個(gè)信號(hào)
?? ??? ??? ?比如段錯(cuò)誤,一旦產(chǎn)生段錯(cuò)誤,進(jìn)程收到這個(gè)信號(hào),此時(shí)輸出信息,然后終止進(jìn)程
?? ??? ?SIGPIPE ? ? ?13 ? ? ? Term ? ?Broken pipe: write to pipe with no
?? ??? ??? ??? ??? ??? ??? ??? ??? ? ?readers; see pipe(7)
?? ??? ??? ?當(dāng)你往一個(gè)管道寫數(shù)據(jù)時(shí),沒有讀端進(jìn)程時(shí)就會(huì)產(chǎn)生這個(gè)信號(hào)
?? ??? ?SIGALRM ? ? ?14 ? ? ? Term ? ?Timer signal from alarm(2)
?? ??? ??? ?定時(shí)信號(hào),在進(jìn)程調(diào)用alarm時(shí),會(huì)在超時(shí)時(shí),產(chǎn)生這個(gè)信號(hào)
?? ??? ?SIGTERM ? ? ?15 ? ? ? Term ? ?Termination signal
?? ??? ?SIGUSR1 ? 30,10,16 ? ?Term ? ?User-defined signal 1
?? ??? ?SIGUSR2 ? 31,12,17 ? ?Term ? ?User-defined signal 2
?? ??? ??? ?用戶自定義信號(hào),這個(gè)信號(hào)所代表的含義由用戶自己去解釋。
?? ??? ?SIGCHLD ? 20,17,18 ? ?Ign ? ? Child stopped or terminated
?? ??? ??? ?當(dāng)子進(jìn)程停止或終止時(shí),父進(jìn)程會(huì)收到這個(gè)信號(hào)
?? ??? ??? ?父進(jìn)程收到這個(gè)信號(hào)之后并不會(huì)如何,因?yàn)榇诵盘?hào)默認(rèn)的處理方式是忽略。
?? ??? ?SIGCONT ? 19,18,25 ? ?Cont ? ?Continue if stopped
?? ??? ?SIGSTOP ? 17,19,23 ? ?Stop ? ?Stop process
?? ??? ??? ?停止進(jìn)程,不可被捕獲和忽略的。
?? ??? ?SIGTSTP ? 18,20,24 ? ?Stop ? ?Stop typed at terminal
?? ??? ?SIGTTIN ? 21,21,26 ? ?Stop ? ?Terminal input for background process
?? ??? ?SIGTTOU ? 22,22,27 ? ?Stop ? ?Terminal output for background process
?? ??? ??? ?前臺(tái)進(jìn)程 后臺(tái)進(jìn)程 進(jìn)程狀態(tài)
?? ??? ?linux下信號(hào)相關(guān)的API函數(shù)
?? ??? ?1)?? ?發(fā)送信號(hào)
?? ??? ??? ?NAME
?? ??? ??? ??? ?kill - send signal to a process
?? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ?#include <sys/types.h>
?? ??? ??? ??? ?#include <signal.h>
?? ??? ??? ??? ?int kill(pid_t pid, int sig);
?? ??? ??? ??? ?kill發(fā)送信號(hào)給進(jìn)程,kill不僅是一個(gè)函數(shù),也是一條指令。
?? ??? ??? ??? ??? ?pid:指定信號(hào)的接受者(可能是多個(gè)進(jìn)程)
?? ??? ??? ??? ??? ??? ?pid > 0 ? ?? ?表示發(fā)送信號(hào)給一個(gè)指定的進(jìn)程
?? ??? ??? ??? ??? ??? ?pid = 0 ?? ?發(fā)送信號(hào)給與調(diào)用進(jìn)程同組的所有進(jìn)程
?? ??? ??? ??? ??? ??? ?pid == -1?? ?發(fā)送信號(hào)給系統(tǒng)所有的進(jìn)程(有權(quán)限發(fā)送的所有進(jìn)程)
?? ??? ??? ??? ??? ??? ?pid < -1?? ?表示發(fā)送信號(hào)給組ID等PID的絕對(duì)值的所有進(jìn)程
?? ??? ??? ??? ??? ?sig:要發(fā)送的信號(hào),請(qǐng)參考上面的宏
?? ??? ??? ??? ??? ?返回值:成功(至少有一個(gè)進(jìn)程成功接收到信號(hào))返回0,失敗返回-1,同時(shí)errno被設(shè)置。
?? ??? ?2)?? ?NAME
?? ??? ??? ??? ?raise - send a signal to the caller
?? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ?#include <signal.h>
?? ??? ??? ??? ?int raise(int sig);
?? ??? ??? ??? ?發(fā)送一個(gè)信號(hào)給自己
?? ??? ??? ??? ?raise(sig) <----> kill(getpid(),sig)
?? ??? ?3)?? ?alarm
?? ??? ??? ?NAME
?? ??? ??? ??? ?alarm - set an alarm clock for delivery of a signal
?? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ?#include <unistd.h>
?? ??? ??? ??? ?unsigned int alarm(unsigned int seconds);
?? ??? ??? ??? ?alarm定時(shí)發(fā)送一個(gè)鬧鐘信號(hào)(SIGALRM)給本進(jìn)程。
?? ??? ??? ??? ?“鬧鐘”:每一個(gè)進(jìn)程都有屬于自己的一個(gè)“鬧鐘”。
?? ??? ??? ??? ??? ??? ?“鬧鐘”時(shí)間到了,進(jìn)程就會(huì)收到一個(gè)SIGALRM的信號(hào),但是同一時(shí)刻一個(gè)進(jìn)程
?? ??? ??? ??? ??? ??? ?只有一個(gè)“鬧鐘”生效。
?? ??? ??? ??? ??? ?seconds:多少秒后,發(fā)送一個(gè)“鬧鐘”信號(hào)。
?? ??? ??? ??? ??? ?alarm(0)--->代表取消一個(gè)“鬧鐘”。
?? ??? ??? ??? ??? ?返回值:返回上一個(gè)鬧鐘的剩余秒數(shù)。
?? ??? ??? ??? ??? ?alarm(5);
?? ??? ??? ??? ??? ?....
?? ??? ??? ??? ??? ?int r = alarm(10);//鬧鐘時(shí)間被重新設(shè)置成10秒,即前面那個(gè)5s的鬧鐘被取消了
?? ??? ?4)?? ?捕捉信號(hào):改變信號(hào)的處理方式
?? ??? ??? ?NAME
?? ??? ??? ??? ?signal - ANSI C signal handling
?? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ?#include <signal.h>
?? ??? ??? ??? ?typedef void (*sighandler_t)(int);
?? ??? ??? ??? ??? ?void (int) * --> sighandler_t
?? ??? ??? ??? ??? ?sighandler_t:是一個(gè)函數(shù)指針的類型。
?? ??? ??? ??? ??? ?它可以用來定義一個(gè)函數(shù)指針類型的變量。
?? ??? ??? ??? ??? ?這個(gè)變量指向一個(gè)無返回值,并帶有一個(gè)int類型參數(shù)的函數(shù)。
?? ??? ??? ??? ?sighandler_t signal(int signum, sighandler_t handler);
?? ??? ??? ??? ??? ?signum:要捕捉的那個(gè)信號(hào)的信號(hào)值
?? ??? ??? ??? ??? ?handler:信號(hào)的處理方式有三種的:
?? ??? ??? ??? ??? ??? ?a. ?? ?自定義的處理函數(shù)
?? ??? ??? ??? ??? ??? ??? ?這個(gè)處理函數(shù)為無返回值的,帶一個(gè)int類型的參數(shù)的函數(shù)。
?? ??? ??? ??? ??? ??? ??? ?大概的格式:
?? ??? ??? ??? ??? ??? ??? ??? ?void my_sig_handler(int sig)
?? ??? ??? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ??? ??? ?//函數(shù)的功能實(shí)現(xiàn)用戶自行決定
?? ??? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ?b.?? ?SIG_IGN:忽略該信號(hào)
?? ??? ??? ??? ??? ??? ?c.?? ?SIG_DFL:采用操作系統(tǒng)默認(rèn)的處理方式。
?? ??? ??? ??? ??? ?返回值:
?? ??? ??? ??? ??? ??? ?成功,返回該信號(hào)上一次的處理方式
?? ??? ??? ??? ??? ??? ?失敗,返回SIG_ERR,同時(shí)errno被設(shè)置。
?? ?(4)?? ?共享內(nèi)存
?? ??? ?如果兩個(gè)進(jìn)程之間要進(jìn)行通信的話,兩個(gè)進(jìn)程之間是不能直接通信的。
?? ??? ?必須要借助于內(nèi)核。
?? ??? ?像之前的管道的通信方式最少要在進(jìn)程間copy兩次,效率有待提高。
?? ??? ?能不能讓多個(gè)進(jìn)程共享一段內(nèi)存---->這段內(nèi)存即是你的,也是我的。
?? ??? ?也就是說你往這段內(nèi)存中寫入數(shù)據(jù),實(shí)際上就是往我的內(nèi)存中寫入數(shù)據(jù)。
?? ??? ?那么我們就把這種進(jìn)程間通信方式稱之為“共享內(nèi)存”。有點(diǎn)類似于“共享文件夾”。
?? ??? ?共享內(nèi)存的通信效率相對(duì)于其它的進(jìn)程間通信手段是最高的。
?? ??? ?共享內(nèi)存的實(shí)現(xiàn)方式:
?? ??? ??? ?在內(nèi)核中開辟一塊共享內(nèi)存,其它進(jìn)程通過“映射”方式獲取這段共享內(nèi)存的引用(指針).
?? ??? ??? ?進(jìn)程A可以映射這段內(nèi)存,同時(shí)其他的進(jìn)程(如:B/C....)也可以映射這段內(nèi)存,
?? ??? ??? ?A往這段內(nèi)存中寫入數(shù)據(jù),實(shí)際上就是往其他進(jìn)程的進(jìn)程地址空間中寫入數(shù)據(jù)。
?? ??? ??? ?反之亦然。
?? ??? ?共享內(nèi)存的實(shí)現(xiàn)有兩種不同的方式:
?? ??? ??? ?一種是System V共享內(nèi)存
?? ??? ??? ?一種是POSIX共享內(nèi)存
?? ??? ??? ?兩種主要是其實(shí)現(xiàn)共享內(nèi)存的方式不一樣,其本質(zhì)是差不多的。
?? ??? ?System V共享內(nèi)存的實(shí)現(xiàn)方式:
?? ??? ??? ?操作流程:
?? ??? ??? ??? ?通過ftok()函數(shù)獲取 ---> System V IPC對(duì)象的key ---> 通過key創(chuàng)建或打開這個(gè)
?? ??? ??? ??? ?IPC的設(shè)施(msg/shm/sem) ---> 通過System V IPC提供的讀/寫函數(shù)來交換數(shù)據(jù)
?? ??? ??? ??? ?---> 關(guān)閉設(shè)施
?? ??? ??? ?如果把一個(gè)IPC設(shè)施(msg/shm/sem)比作是一個(gè)內(nèi)核中的房間,這個(gè)房間就會(huì)有一個(gè)鑰匙(KEY)
?? ??? ??? ?多個(gè)進(jìn)程如果要用IPC設(shè)施進(jìn)行通信的話,就必須要確保多個(gè)進(jìn)程進(jìn)入同一個(gè)房間(設(shè)施)。
?? ??? ?a.?? ?ftok用來創(chuàng)建一個(gè)System V IPC設(shè)施的KEY
?? ??? ??? ?NAME
?? ??? ??? ??? ?ftok - convert a pathname and a project identifier to a System V IPC key
?? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ?#include <sys/types.h>
?? ??? ??? ??? ?#include <sys/ipc.h>
?? ??? ??? ??? ?key_t ftok(const char *pathname, int proj_id);
?? ??? ??? ??? ?key_t ---> int
?? ??? ??? ??? ?函數(shù)參數(shù):
?? ??? ??? ??? ??? ?pathname:一個(gè)文件系統(tǒng)中的路徑名(必須是要存在的并且有權(quán)限讀取的)
?? ??? ??? ??? ??? ?“/home” "/mnt" ......
?? ??? ??? ??? ??? ?proj_id:整數(shù)。這個(gè)參數(shù)存在的意義在于讓一個(gè)文件也能生成多個(gè)key值。
?? ??? ??? ??? ??? ??? ?ftok利用同一個(gè)文件最多可以得到的key鍵值256個(gè),因?yàn)閒tok只取
?? ??? ??? ??? ??? ??? ?proj_id值二進(jìn)制的低8bit位。
?? ??? ??? ??? ??? ?ftok("/home",1); 與 ftok("/home",257);生成的鍵值是一樣的。
?? ??? ??? ??? ?返回值:
?? ??? ??? ??? ??? ?成功生成一個(gè)唯一性的System V IPC的key,失敗返回-1,同時(shí)errno被設(shè)置。
?? ??? ??? ??? ?key值其實(shí)就是一個(gè)32位的int,key的生成是根據(jù)pathname和proj_id來的。
?? ??? ??? ??? ?具體其實(shí)是按照pathname指定的文件(目錄)的屬性,也就是說struct stat
?? ??? ??? ??? ?結(jié)構(gòu)體st_dev的第八位和st_ino的低十六位和proj_id的低八位混合組成。
?? ??? ?b.?? ?shmget - allocates a System V shared memory segment
?? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ?#include <sys/ipc.h>
?? ??? ??? ??? ?#include <sys/shm.h>
?? ??? ??? ??? ?int shmget(key_t key, size_t size, int shmflg);
?? ??? ??? ??? ?創(chuàng)建或打開System V共享內(nèi)存
?? ??? ??? ??? ??? ?key:一般由ftok的返回值獲得。
?? ??? ??? ??? ??? ?size:以字節(jié)為按位指定共享內(nèi)存區(qū)域的大小。
?? ??? ??? ??? ??? ??? ?當(dāng)實(shí)際操作為創(chuàng)建一個(gè)新的共享內(nèi)存區(qū)域時(shí),必須指定一個(gè)不為0的size值
?? ??? ??? ??? ??? ??? ?(PAGE_SIZE的整數(shù)倍,PAGE_SIZE:4K)。
?? ??? ??? ??? ??? ??? ?如果實(shí)際操作為訪問一個(gè)已經(jīng)存在的共享內(nèi)存區(qū)域,那么size就為0。
?? ??? ??? ??? ??? ?shmflg:標(biāo)志位
?? ??? ??? ??? ??? ??? ?如果是創(chuàng)建共享內(nèi)存 ?IPC_CREAT | 權(quán)限位
?? ??? ??? ??? ??? ??? ?如果是打開貢獻(xiàn)內(nèi)存 ?0
?? ??? ??? ??? ??? ?其實(shí)你完全可以按照創(chuàng)建的方式指定也可以,因?yàn)樵诖蜷_共享內(nèi)存時(shí),如果
?? ??? ??? ??? ??? ?發(fā)現(xiàn)key對(duì)應(yīng)的共享內(nèi)存已經(jīng)存在了,那么它會(huì)自動(dòng)忽略后面的選項(xiàng),直接打開。
?? ??? ??? ??? ??? ?注意:
?? ??? ??? ??? ??? ??? ?共享內(nèi)存一旦創(chuàng)建,那么它的存在是隨內(nèi)核的持續(xù)性,即就算使用(創(chuàng)建)它
?? ??? ??? ??? ??? ??? ?的進(jìn)程結(jié)束了,這塊共享內(nèi)存也存在,除非顯式的去釋放掉它。
?? ??? ??? ??? ??? ?返回值:
?? ??? ??? ??? ??? ??? ?成功返回新創(chuàng)建或打開的共享內(nèi)存的ID號(hào)。失敗返回-1,同時(shí)errno被設(shè)置。
?? ??? ?c.?? ?映射
?? ??? ??? ?NAME
?? ??? ??? ??? ?shmat, shmdt - System V shared memory operations
?? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ?#include <sys/types.h>
?? ??? ??? ??? ?#include <sys/shm.h>
?? ??? ??? ??? ?void *shmat(int shmid, const void *shmaddr, int shmflg);
?? ??? ??? ??? ??? ?將內(nèi)核中的共享內(nèi)存映射到進(jìn)程的地址空間中去
?? ??? ??? ??? ??? ?shmid:要映射的共享內(nèi)存區(qū)域的ID(shmget的返回值)
?? ??? ??? ??? ??? ?shmaddr:指向要映射到進(jìn)程的哪個(gè)地址上去。
?? ??? ??? ??? ??? ??? ?一般為NULL,表示由操作系統(tǒng)自行決定。
?? ??? ??? ??? ??? ?shmflg:(1)?? ?SHM_RDONLY 只讀
?? ??? ??? ??? ??? ??? ??? ?(2)?? ?0 讀寫
?? ??? ??? ??? ??? ?返回值:成功返回映射后的首地址,失敗返回NULL,同時(shí)errno被設(shè)置.
?? ??? ?d.?? ?解映射
?? ??? ??? ?int shmdt(const void *shmaddr);
?? ??? ??? ?用來解映射一段共享內(nèi)存
?? ??? ??? ?shmaddr:要解映射的那個(gè)地址
?? ??? ??? ?返回值:成功返回0,失敗返回-1,同時(shí)errno被設(shè)置
?? ??? ?e.?? ?其他控制操作,如刪除....
?? ??? ??? ?NAME
?? ??? ??? ??? ?shmctl - System V shared memory control
?? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ?#include <sys/ipc.h>
?? ??? ??? ??? ?#include <sys/shm.h>
?? ??? ??? ??? ?int shmctl(int shmid, int cmd, struct shmid_ds *buf);
?? ??? ??? ??? ??? ?shmid:要進(jìn)行控制操作命令的共享內(nèi)存區(qū)域的ID
?? ??? ??? ??? ??? ?cmd:操作命令,不同的命令第三參數(shù)不一樣。
?? ??? ??? ??? ??? ??? ?IPC_RMID ? ?刪除指定的共享內(nèi)存區(qū)域
?? ??? ??? ??? ??? ?buf:if cmd == IPC_RMID ?buf為NULL
?? ??? ??? ??? ??? ?返回值:成功返回0,失敗返回-1,同時(shí)errno被設(shè)置。
?? ??? ?寫一個(gè)程序,來播放一個(gè)目錄下面的影視文件(mp3/mp4),要實(shí)現(xiàn)一些基本的功能
?? ??? ??? ?快進(jìn)/快退/暫停/退出/播放上一個(gè)/播放下一個(gè)....
?? ??? ??? ?整個(gè)項(xiàng)目基于mplayer多媒體播放器
?? ??? ??? ?-slave ?從模式
?? ??? ??? ?默認(rèn)mplayer是從鍵盤上獲取控制信息的,mplayer另外提供了一種更為靈活的控制方式,
?? ??? ??? ?用來進(jìn)行播放控制---slave模式。
?? ??? ??? ?在slave模式下,mplayer為后臺(tái)運(yùn)行其他程序,不再截獲鍵盤事件,mplayer會(huì)從標(biāo)準(zhǔn)輸入讀
?? ??? ??? ?一個(gè)換行符\n分隔開的命令。
?? ??? ??? ?查看mplayer所支持的所有slave模式下命令:
?? ??? ??? ??? ?mplayer -input cmdlist
?? ??? ??? ?操作命令去控制mplyer的方式有兩種:
?? ??? ??? ??? ?a. ?? ?從控制臺(tái)輸入控制命令(在終端上使用)
?? ??? ??? ??? ??? ?在終端上輸入指令:
?? ??? ??? ??? ??? ??? ?mplayer -slave -quiet 1.mp4
?? ??? ??? ??? ??? ??? ?-slave:啟動(dòng)從模式
?? ??? ??? ??? ??? ??? ?-quiet:不輸出冗余的信息
?? ??? ??? ??? ??? ?此時(shí)mplayer已經(jīng)啟動(dòng)
?? ??? ??? ??? ??? ?loadfile string ?? ??? ?//參數(shù)sting為播放文件的名字
?? ??? ??? ??? ??? ?volume 100 1?? ??? ??? ?//設(shè)置音量,中間的為音量的大小
?? ??? ??? ??? ??? ?mute 1/0?? ??? ??? ??? ?//靜音開關(guān) 1:靜音 0:開啟音量
?? ??? ??? ??? ??? ?pause?? ??? ??? ??? ??? ?//暫停/取消暫停
?? ??? ??? ??? ??? ?seek value ?? ??? ??? ??? ?//快進(jìn)/快退,參數(shù)value為秒數(shù)
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//value為正數(shù)表示前進(jìn)value秒
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//value為正數(shù)表示后退value秒
?? ??? ??? ??? ??? ?seek value 1?? ??? ??? ?//意味著跳轉(zhuǎn)到百分之value處
?? ??? ??? ??? ??? ?quit?? ??? ??? ??? ??? ?//退出
?? ??? ??? ??? ??? ?get_time_length ?? ??? ?//返回播放文件的長度,以秒為單位
?? ??? ??? ??? ??? ?get_percent_pos?? ??? ??? ?//按百分比輸出當(dāng)前的播放進(jìn)度
?? ??? ??? ??? ??? ?get_time_pos ?? ??? ??? ?//把文件當(dāng)前播放的秒鐘數(shù)以浮點(diǎn)型打印出來
?? ??? ??? ??? ??? ?get_file_name ?? ??? ??? ?//獲取當(dāng)前播放文件的名字
?? ??? ??? ??? ?b.?? ?從有名管道(fifo)輸入控制命令(在代碼中使用)
?? ??? ??? ??? ??? ?我們可以用指令指定mplayer從有名管道中獲取指令,那么我們要做的就是
?? ??? ??? ??? ??? ?在代碼中往管道中同樣的寫入上述指令即可控制mplayer。
?? ??? ??? ??? ??? ?指定mplayer從哪個(gè)管道中獲取指令:
?? ??? ??? ??? ??? ??? ?mplayer -slave -input file=xxx.fifo
?? ??? ??? ??? ?總結(jié)一下,mplayer完整的指令:
?? ??? ??? ??? ??? ?mplayer -slave -quiet -input file=xxx.fifo -zoom -x 800 -y 480 1.mp4
?? ??? ??? ?exec
?? ??? ??? ?c = getchar();
?? ??? ??? ?if(c == 'p')
?? ??? ??? ?{
?? ??? ??? ??? ?write(xxx.fifo,"pause\n",sizeof("pause\n"));
?? ??? ??? ?}
?? ??? ??? ?else if(c == 'a')
?? ??? ??? ?{
?? ??? ??? ??? ?write(xxx.fifo,"seek 5\n",sizeof("seek 5\n"));
?? ??? ??? ?}
?? ??? ??? ?x,y;
?? ??? ??? ?if()
?? ?(5)?? ?信號(hào)量
?? ? ? ?如果有兩個(gè)或兩個(gè)以上的任務(wù)(進(jìn)程/線程),去訪問同一個(gè)共享資源,那么我們就必須要保證
?? ??? ?這個(gè)共享資源的有序訪問,否則將會(huì)發(fā)生不可預(yù)知的后果。
?? ??? ?例子:
?? ??? ? ? ?i = 5;//i是處于某塊共享內(nèi)存中的變量
?? ??? ??? ?fun()
?? ??? ??? ?{
?? ??? ??? ??? ?i++;
?? ??? ??? ?}
?? ??? ??? ?i的值有以下幾種情況:
?? ??? ??? ?i == 7(應(yīng)該是要等于7,才是我們期望看到的結(jié)果)
?? ??? ??? ?i == 6(也有可能是6,這個(gè)不是我們期望看到的結(jié)果)
?? ??? ??? ?那么怎么去解決這個(gè)問題呢?
?? ??? ??? ?造成這個(gè)問題的原因是進(jìn)程對(duì)同一個(gè)資源訪問不是有序的。
?? ??? ??? ?也就是說一個(gè)進(jìn)程在訪問一個(gè)資源的同時(shí),其他進(jìn)程也在訪問。進(jìn)程之間就在競爭的關(guān)系。
?? ??? ??? ?所以我們需要對(duì)這個(gè)共享資源進(jìn)行某種方式的保護(hù),以使他被有序的訪問,
?? ??? ??? ?避免競爭。
?? ??? ??? ?同樣的,對(duì)應(yīng)在程序的執(zhí)行上也是一樣的:
?? ??? ??? ?我們是因?yàn)椴l(fā)-->競爭-->共享資源的非法訪問-->程序行為異常
?? ??? ??? ?應(yīng)該要在保留并發(fā)的前提下,避免競爭,也就是說在多個(gè)進(jìn)程訪問同一個(gè)共享資源的時(shí)候,
?? ??? ??? ?要嚴(yán)格串行。
?? ??? ??? ?那么這種避免競爭的機(jī)制就是我們今天要講的信號(hào)量。
?? ??? ??? ?1)?? ?信號(hào)量機(jī)制
?? ??? ??? ??? ?信號(hào)量(semaphore)是一種用于提供不同進(jìn)程間或一個(gè)進(jìn)程內(nèi)部不用線程間同步的
?? ??? ??? ??? ?一種機(jī)制。
?? ??? ??? ??? ?我們把進(jìn)程/線程/任務(wù)稱之為叫并發(fā)的實(shí)體。
?? ??? ??? ??? ?同步:并發(fā)的實(shí)體間互相等待,相互制約,有序的,有條件的訪問共享資源。
?? ??? ??? ??? ?所以這個(gè)信號(hào)量就是為了保護(hù)共享資源,讓共享資源有序訪問的一種機(jī)制。
?? ??? ??? ??? ?信號(hào)量是我們程序界最高尚的一個(gè)東西,因?yàn)樗皇菫榱俗约憾嬖诘?#xff0c;
?? ??? ??? ??? ?而是為了別人(它保護(hù)的對(duì)象-->共享資源)而存在的,它不是用來傳送數(shù)據(jù)的,
?? ??? ??? ??? ?而是用來協(xié)調(diào)各進(jìn)程/線程間工作用的。
?? ??? ??? ??? ?什么時(shí)候需要使用信號(hào)量?
?? ??? ??? ??? ?有保護(hù)的對(duì)象的時(shí),才需要信號(hào)量。
?? ??? ??? ?2)?? ?如何去保護(hù)呢?
?? ??? ??? ??? ?“保護(hù)”是指:讓這個(gè)被保護(hù)的對(duì)象(共享資源)有序訪問。比如“互斥”。
?? ??? ??? ??? ?“互斥”:我在訪問的時(shí)候你不能訪問。
?? ??? ??? ??? ?
?? ??? ??? ?3) ?? ?信號(hào)量是如何實(shí)現(xiàn)的
?? ??? ??? ??? ?信號(hào)量本質(zhì)上是一個(gè)整數(shù)。
?? ??? ??? ??? ?
?? ??? ??? ??? ?用來表示資源的數(shù)量。如果這個(gè)數(shù)為0表示資源不可用,如果這個(gè)數(shù)大于0表示資源可用。
?? ??? ??? ??? ?
?? ??? ??? ??? ?一個(gè)進(jìn)程或線程可以坐在某個(gè)信號(hào)量上執(zhí)行如下三種操作:
?? ??? ??? ??? ?a.?? ?創(chuàng)建一個(gè)信號(hào)量:這還要求調(diào)用者指定信號(hào)量的初始值。
?? ??? ??? ??? ??? ?初始值表示該信號(hào)量保護(hù)的共享資源可以同時(shí)被多少個(gè)任務(wù)所訪問。
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ?b.?? ?等待(wait)一個(gè)信號(hào)量
?? ??? ??? ??? ??? ?該操作會(huì)判斷這個(gè)信號(hào)量的值,如果其值<=0,那么會(huì)等待(阻塞)
?? ??? ??? ??? ??? ?一旦其值>0,這個(gè)時(shí)候,將它-1,接著訪問臨界資源了。
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?我們把多個(gè)進(jìn)程/線程可能同時(shí)訪問的資源,稱之為共享資源或臨界資源。
?? ??? ??? ??? ??? ?把訪問臨界資源的代碼,稱之為臨界區(qū)。
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?程序進(jìn)入臨界區(qū)之前,必須對(duì)資源進(jìn)行申請(qǐng),這種操作稱之為P操作。
?? ??? ??? ??? ??? ?申請(qǐng)成功,資源數(shù)量(信號(hào)量值)就減少,申請(qǐng)失敗,要么等,要么走。
?? ??? ??? ??? ?c.?? ?釋放一個(gè)信號(hào)量
?? ??? ??? ??? ??? ?該操作將信號(hào)量的值+1。
?? ??? ??? ??? ??? ?程序離開臨界區(qū)后,必須釋放相應(yīng)的資源,這個(gè)操作我們稱之為V操作。
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?總結(jié):
?? ??? ??? ??? ??? ??? ?P操作為資源減操作,V操作為資源的加操作。
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?兩者都屬于原子操作:是指不會(huì)被調(diào)度機(jī)制打斷的操作。
?? ??? ??? ??? ??? ?這種操作一旦開始,就一直運(yùn)行到結(jié)束,也就是說原子操作是不可被分隔的。
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ?思考:
?? ??? ??? ??? ??? ?1.?? ?現(xiàn)在有五個(gè)資源A,B,C,D,E需要去保護(hù),設(shè)計(jì)師決定用一個(gè)信號(hào)量s來
?? ??? ??? ??? ??? ??? ?同時(shí)保護(hù)這五個(gè)資源。
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?這種設(shè)計(jì)可以達(dá)到互斥訪問的目的。
?? ??? ??? ??? ??? ??? ?降低了并發(fā)度,因?yàn)槲鍌€(gè)資源本身是可以被同時(shí)訪問的。
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?2.?? ?現(xiàn)在有五個(gè)資源A,B,C,D,E需要去保護(hù),設(shè)計(jì)師決定用五個(gè)信號(hào)量s1、s2
?? ??? ??? ??? ??? ??? ?s3、s4、s5來同時(shí)保護(hù)這五個(gè)資源。
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?3.?? ?有一種這樣的情況,大家談?wù)撘幌?#xff1a;
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?如上這種情況我們把其稱之為deadlock(死鎖)。
?? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ?4)?? ?信號(hào)量API函數(shù)
?? ??? ??? ??? ?信號(hào)量的使用流程:
?? ??? ??? ??? ??? ?a.?? ?生成key(ftok)
?? ??? ??? ??? ??? ?b.?? ?創(chuàng)建或獲取信號(hào)量
?? ??? ??? ??? ??? ?c.?? ?信號(hào)量的初始化
?? ??? ??? ??? ??? ?d.?? ?PV操作
?? ??? ??? ??? ??? ?e.?? ?信號(hào)量的刪除
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ?信號(hào)量分為兩種:
?? ??? ??? ??? ??? ?System V信號(hào)量和POSIX信號(hào)量
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ?4.1)System V信號(hào)量
?? ??? ??? ??? ??? ?System V信號(hào)量分為兩種:
?? ??? ??? ??? ??? ?互斥信號(hào)量:該信號(hào)量的值要么是1,要么是0.
?? ??? ??? ??? ??? ??? ?它所保護(hù)的共享資源同一時(shí)刻只允許一個(gè)任務(wù)去訪問它。
?? ??? ??? ??? ?
?? ??? ??? ??? ??? ?計(jì)數(shù)信號(hào)量:
?? ??? ??? ??? ??? ??? ?該信號(hào)量的值可以是>1的值,它所保護(hù)的共享資源允許多個(gè)任務(wù)同時(shí)去訪問它。
?? ??? ??? ??? ??? ??? ?如果計(jì)數(shù)信號(hào)量的計(jì)數(shù)值為1,0.那么可以將其看成是互斥信號(hào)量。
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?那么System V中采用計(jì)數(shù)信號(hào)量集。
?? ??? ??? ??? ??? ?計(jì)數(shù)信號(hào)量集是由一個(gè)或者多個(gè)計(jì)數(shù)信號(hào)量構(gòu)成的集合。計(jì)數(shù)信號(hào)量集其實(shí)就是
?? ??? ??? ??? ??? ?一個(gè)計(jì)數(shù)信號(hào)量數(shù)組,POSIX信號(hào)量采用計(jì)數(shù)信號(hào)量。
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?為什么system V要把信號(hào)量弄一個(gè)信號(hào)量集(數(shù)組)?
?? ??? ??? ??? ??? ??? ?因?yàn)橐粋€(gè)資源對(duì)應(yīng)一個(gè)信號(hào)量,我們有時(shí)可能要去訪問多個(gè)資源,
?? ??? ??? ??? ??? ??? ?那么我就需要去對(duì)多個(gè)信號(hào)量進(jìn)行P操作,依次去對(duì)每一個(gè)信號(hào)量進(jìn)行P
?? ??? ??? ??? ??? ??? ?操作太過于麻煩,而且有可能會(huì)造成死鎖,如果弄一個(gè)信號(hào)量集,
?? ??? ??? ??? ??? ??? ?當(dāng)我需要對(duì)多個(gè)信號(hào)量進(jìn)行V操作或P操作時(shí),直接對(duì)信號(hào)量集進(jìn)行PV操作
?? ??? ??? ??? ??? ??? ?就相當(dāng)于對(duì)信號(hào)量集中每一個(gè)信號(hào)量進(jìn)行PV操作。
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?課外拓展:解決死鎖的方法最著名的算法是銀行家算法。
?? ??? ??? ??? ?
?? ??? ??? ??? ??? ?1.?? ?semget 用來創(chuàng)建或打開一個(gè)system v信號(hào)量
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?NAME
?? ??? ??? ??? ??? ??? ??? ?semget - get a System V semaphore set identifier
?? ??? ??? ??? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ??? ??? ??? ?#include <sys/types.h>
?? ??? ??? ??? ??? ??? ??? ?#include <sys/ipc.h>
?? ??? ??? ??? ??? ??? ??? ?#include <sys/sem.h>
?? ??? ??? ??? ??? ??? ??? ?int semget(key_t key, int nsems, int semflg)
?? ??? ??? ??? ??? ??? ??? ??? ?key:System V IPC對(duì)象的key(一般由ftok返回)
?? ??? ??? ??? ??? ??? ??? ??? ?nsems:你要?jiǎng)?chuàng)建的信號(hào)量集中信號(hào)量的數(shù)量。
?? ??? ??? ??? ??? ??? ??? ??? ??? ?如果我們不是創(chuàng)建而是去打開一個(gè)已經(jīng)存在的信號(hào)量集。
?? ??? ??? ??? ??? ??? ??? ??? ??? ?此處這個(gè)參數(shù)應(yīng)該要填0.一旦創(chuàng)建完一個(gè)信號(hào)量集
?? ??? ??? ??? ??? ??? ??? ??? ??? ?其信號(hào)量集中的信號(hào)量的個(gè)數(shù)就不能被改變了。
?? ??? ??? ??? ??? ??? ??? ??? ?semflg:
?? ??? ??? ??? ??? ??? ??? ??? ??? ?(1)?? ?創(chuàng)建 ?IPC_CREAT | 權(quán)限位
?? ??? ??? ??? ??? ??? ??? ??? ??? ?(2)?? ?打開 ?0
?? ??? ??? ??? ??? ??? ??? ??? ?返回值:成功返回system v信號(hào)量集的ID。
?? ??? ??? ??? ??? ??? ??? ??? ??? ?失敗返回-1,同時(shí)errno被設(shè)置。
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?2.?? ?semctl:控制操作(設(shè)置或者獲取信號(hào)量集中某個(gè)或者某些信號(hào)量的值)
?? ??? ??? ??? ??? ??? ?NAME
?? ??? ??? ??? ??? ??? ??? ?semctl - System V semaphore control operations
?? ??? ??? ??? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ??? ??? ??? ?#include <sys/types.h>
?? ??? ??? ??? ??? ??? ??? ?#include <sys/ipc.h>
?? ??? ??? ??? ??? ??? ??? ?#include <sys/sem.h>
?? ??? ??? ??? ??? ??? ??? ?int semctl(int semid, int semnum, int cmd, ...);
?? ??? ??? ??? ??? ??? ??? ??? ?semid:要操作的信號(hào)量集的id(semget的返回值)。
?? ??? ??? ??? ??? ??? ??? ??? ?semnum:要操作的信號(hào)量集中的哪個(gè)信號(hào)量。
?? ??? ??? ??? ??? ??? ??? ??? ??? ?就是信號(hào)量數(shù)組的下標(biāo),從0開始,到nsems-1結(jié)束.
?? ??? ??? ??? ??? ??? ??? ??? ?cmd:
?? ??? ??? ??? ??? ??? ??? ??? ??? ?命令號(hào),常用的有:
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?GETVAL:獲取第semnum個(gè)信號(hào)量的值
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?SETVAL:設(shè)置第smenum個(gè)信號(hào)量的值
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?GETALL:獲取這個(gè)信號(hào)量集中所有信號(hào)量的值
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?SETALL:設(shè)置這個(gè)信號(hào)量集中所有信號(hào)量的值
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?IPC_RMID:刪除這個(gè)信號(hào)量集。
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?.....
?? ??? ??? ??? ??? ??? ??? ??? ?針對(duì)第四個(gè)參數(shù):
?? ??? ??? ??? ??? ??? ??? ??? ??? ?cmd == IPC_RMID
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?沒有第四個(gè)參數(shù)
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?如:semctl(semid,0,IPC_RMID);
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?cmd == GETVAL,第四個(gè)參數(shù)也不要
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?函數(shù)返回值就表示那個(gè)信號(hào)量的值
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?如:
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?int val = semctl(semid,2,GETVAL);
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?用來獲取semid指定的信號(hào)量集中第3個(gè)信號(hào)量的值
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?cmd == SETVAL
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?第四個(gè)參數(shù)應(yīng)為int,表示要設(shè)置信號(hào)量的值
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?如:
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?int sem_val = 1;
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?int r = semctl(semid,1,SETVAL,semval);
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?cmd == GETALL
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?第四個(gè)參數(shù)應(yīng)為unsinged short vals[]
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?這個(gè)數(shù)組是用來保存獲取的每一個(gè)信號(hào)量的值的。
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?如:
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?unsigned short vals[10];
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?int r = semctl(semid,0,GETALL,vals);
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//vals[0] 保存的就是第一個(gè)信號(hào)量的值
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?...
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?cmd == SETALL
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?第四個(gè)參數(shù)應(yīng)為unsinged short vals[]
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?這個(gè)數(shù)組是用來設(shè)置每一個(gè)信號(hào)量的值
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?如:
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?unsigned short vals[10] = {1,1,1,1,1,1,1,1,1,1};
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?int r = semctl(semid,0,SETALL,vals);
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//第1個(gè)信號(hào)量的值為1
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?...
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?返回值:根據(jù)不同的命令,semctl返回值的含義也不一樣。
?? ??? ??? ??? ??? ??? ??? ??? ??? ?cmd == GETVAL.
?? ??? ??? ??? ??? ??? ??? ??? ??? ?一般情況下,0-->成功 ? ?-1-->失敗
?? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?3.?? ?semop:system V信號(hào)量的P/V操作
?? ??? ??? ??? ??? ??? ?NAME
?? ??? ??? ??? ??? ??? ??? ?semop, semtimedop - System V semaphore operations
?? ??? ??? ??? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ??? ??? ?#include <sys/types.h>
?? ??? ??? ??? ??? ??? ?#include <sys/ipc.h>
?? ??? ??? ??? ??? ??? ?#include <sys/sem.h>
?? ??? ??? ??? ??? ??? ??? ?int semop(int semid, struct sembuf *sops, size_t nsops);
?? ??? ??? ??? ??? ??? ??? ??? ?semid:要操作的是哪一個(gè)信號(hào)量集
?? ??? ??? ??? ??? ??? ??? ??? ?在system V的信號(hào)量的P/V操作,用一個(gè)結(jié)構(gòu)體struct sembuf?
?? ??? ??? ??? ??? ??? ??? ??? ?描述P/V操作。
?? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?struct sembuf
?? ??? ??? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ??? ??? ?unsigned short sem_num; ?/* semaphore number */
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//要進(jìn)行PV操作的信號(hào)量在信號(hào)量集中的編號(hào)(下標(biāo))
?? ??? ??? ??? ??? ??? ??? ??? ??? ?short ? ? ? ? ?sem_op; ? /* semaphore operation */
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//要進(jìn)行的操作的類型
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?> 0 ---> V操作 unlock
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?= 0 ---> try一try,看是否會(huì)阻塞(是否能訪問)
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?< 0 ---> P操作 lock
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?semval(信號(hào)量的值) = 原來semval + sem_op;
?? ??? ??? ??? ??? ??? ??? ??? ??? ?short ? ? ? ? ?sem_flg; ?/* operation flags */
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?0:默認(rèn),如果P操作獲取不了,則會(huì)阻塞。
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?IPC_NOWAIT:非阻塞,不等待
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?如果P操作能獲取則獲取,不能獲取則走人(返回-1)
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?SEM_UNDO :?? ?撤銷
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?為了防止進(jìn)程帶鎖退出
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?如果進(jìn)程突然中止,自動(dòng)釋放資源。?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?};
?? ??? ??? ??? ??? ??? ??? ??? ?sops:struct sembuf的數(shù)組
?? ??? ??? ??? ??? ??? ??? ??? ?nsops:這個(gè)第二個(gè)參數(shù)sops數(shù)組中的元素的個(gè)數(shù)
?? ??? ??? ??? ??? ??? ??? ??? ??? ?或者說信號(hào)量集中要進(jìn)行PV操作的信號(hào)量的個(gè)數(shù)
?? ??? ??? ??? ??? ??? ??? ??? ?返回值:
?? ??? ??? ??? ??? ??? ??? ??? ??? ?成功返回0,失敗返回-1,同時(shí)errno被設(shè)置。
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?注意:semop可能會(huì)阻塞當(dāng)前進(jìn)程/線程.
?? ??? ??? ??? ??? ??? ??? ??? ??? ?如果是P操作,獲取不了的時(shí)候,且IPC_NOWAIT沒有設(shè)置的時(shí)候
?? ??? ??? ??? ??? ??? ??? ??? ??? ?會(huì)等待。
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ?int semtimedop(int semid, struct sembuf *sops, size_t nsops,
?? ??? ??? ??? ??? ??? ??? ? ?const struct timespec *timeout);
?? ??? ??? ??? ??? ??? ??? ??? ?限時(shí)等待。
?? ??? ??? ??? ??? ??? ??? ??? ?第四個(gè)參數(shù)timeout描述“超時(shí)”:如果在這段時(shí)間內(nèi),沒有等到資源
?? ??? ??? ??? ??? ??? ??? ??? ?,就不等啦,直接返回。
?? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?struct timespec {
?? ??? ??? ??? ??? ??? ??? ??? ??? ?long ? ?tv_sec; ? ? ? ? /* seconds */
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//秒數(shù)
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?long ? ?tv_nsec; ? ? ? ?/* nanoseconds */
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//納秒
?? ??? ??? ??? ??? ??? ??? ??? ?};
?? ?
?? ??? ??? ??? ??? ??? ??? ??? ?如:
?? ??? ??? ??? ??? ??? ??? ??? ??? ?struct timespec tv;
?? ??? ??? ??? ??? ??? ??? ??? ??? ?tv.tv_sec = 5;
?? ??? ??? ??? ??? ??? ??? ??? ??? ?tv.tv_nsec = 0;
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ?
?? ??? ??? ?作業(yè):
?? ??? ??? ??? ?使用信號(hào)量和共享內(nèi)存,實(shí)現(xiàn)文件的傳輸。
?? ??? ??? ??? ?提示:可以使用兩個(gè)信號(hào)量,一個(gè)初始化為1,一個(gè)初始化為0。
?? ??? ??? ??? ?4.2) POSIX信號(hào)量 ---> 單個(gè)信號(hào)量,非System V的信號(hào)量集
?? ??? ??? ??? ??? ?POSIX信號(hào)量與System V信號(hào)量原理上是一樣的。
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?POSIX信號(hào)量分為兩種:
?? ??? ??? ??? ??? ?1.有名信號(hào)量
?? ??? ??? ??? ??? ??? ?在文件系統(tǒng)中有一個(gè)名字,即意味著有一個(gè)對(duì)應(yīng)的inode結(jié)點(diǎn)
?? ??? ??? ??? ??? ??? ?但是信號(hào)量的內(nèi)容(值)卻是存在于內(nèi)核中的。
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?一般用于任意進(jìn)程或線程間通信。
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?有名信號(hào)量的操作一般有:
?? ??? ??? ??? ??? ??? ??? ?sem_open/sem_wait/sem_post/sem_close
?? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?2.無名信號(hào)量
?? ??? ??? ??? ??? ??? ?沒有名字,無名信號(hào)量存在于內(nèi)存中。
?? ??? ??? ??? ??? ??? ?一般用于任意線程間或有親緣關(guān)系的進(jìn)程間。
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?無名信號(hào)量的操作一般有:
?? ??? ??? ??? ??? ??? ??? ?sem_init/sem_wait/sem_post/sem_destory
?? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?相關(guān)的API函數(shù):
?? ??? ??? ??? ??? ?1.?? ?創(chuàng)建或打開一個(gè)POSIX信號(hào)量
?? ??? ??? ??? ??? ??? ?有名信號(hào)量:
?? ??? ??? ??? ??? ??? ?NAME
?? ??? ??? ??? ??? ??? ??? ?sem_open - initialize and open a named semaphore
?? ??? ??? ??? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ??? ??? ??? ?#include <fcntl.h> ? ? ? ? ? /* For O_* constants */
?? ??? ??? ??? ??? ??? ??? ?#include <sys/stat.h> ? ? ? ?/* For mode constants */
?? ??? ??? ??? ??? ??? ??? ?#include <semaphore.h>
?? ??? ??? ??? ??? ??? ??? ?sem_t *sem_open(const char *name, int oflag);
?? ??? ??? ??? ??? ??? ??? ??? ?name:要?jiǎng)?chuàng)建或打開的POSIX有名信號(hào)量在文件系統(tǒng)中的路徑名。
?? ??? ??? ??? ??? ??? ??? ??? ??? ?要求以‘/’開頭的路徑名(路徑名中只能有一個(gè)/)
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?如:“/test.sem”
?? ??? ??? ??? ??? ??? ??? ??? ??? ?也就是說你的有名信號(hào)量必須放在根目錄下面。
?? ??? ??? ??? ??? ??? ??? ??? ?oflag:
?? ??? ??? ??? ??? ??? ??? ??? ??? ?(1) 打開 ?0
?? ??? ??? ??? ??? ??? ??? ??? ??? ?(2) O_CREAT?? ?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?如果你是打開則只需要兩個(gè)參數(shù),如果是創(chuàng)建則帶四個(gè)參數(shù)
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ?sem_t *sem_open(const char *name, int oflag,
?? ??? ??? ??? ??? ??? ??? ?mode_t mode, unsigned int value);
?? ??? ??? ??? ??? ??? ??? ??? ?mode:指定有名信號(hào)量的創(chuàng)建權(quán)限,有兩種方式去指定的:
?? ??? ??? ??? ??? ??? ??? ??? ??? ?(1)?? ?S_IRUSR...
?? ??? ??? ??? ??? ??? ??? ??? ??? ?(2)?? ?0664
?? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?value:指定創(chuàng)建的有名信號(hào)量的初始值
?? ??? ??? ??? ??? ??? ??? ?返回值:
?? ??? ??? ??? ??? ??? ??? ??? ?成功返回一個(gè)sem_t指針,指向POSIX有名信號(hào)量
?? ??? ??? ??? ??? ??? ??? ??? ?失敗返回一個(gè)SEM_FAILED,同時(shí)errno被設(shè)置。
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?無名信號(hào)量:
?? ??? ??? ??? ??? ??? ?NAME
?? ??? ??? ??? ??? ??? ??? ?sem_init - initialize an unnamed semaphore
?? ??? ??? ??? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ??? ??? ??? ?#include <semaphore.h>
?? ??? ??? ??? ??? ??? ??? ?int sem_init(sem_t *sem, int pshared, unsigned int value);
?? ??? ??? ??? ??? ??? ??? ??? ?sem:指向要初始化的無名信號(hào)量
?? ??? ??? ??? ??? ??? ??? ??? ??? ?一般情況下我們會(huì)先定義或分配一個(gè)無名信號(hào)量 sem_t
?? ??? ??? ??? ??? ??? ??? ??? ??? ?sem_t *psem = malloc(sizeof(sem_t));
?? ??? ??? ??? ??? ??? ??? ??? ?pshared:該無名信號(hào)量的共享方式
?? ??? ??? ??? ??? ??? ??? ??? ??? ?0:進(jìn)程內(nèi)部的線程共享
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?也就是sem指向的地址是進(jìn)程內(nèi)部的地址
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?如malloc開辟出來的空間
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?1:不同進(jìn)程間共享
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?也就說sem指向的地址是內(nèi)核共享內(nèi)存區(qū)域。
?? ??? ??? ??? ??? ??? ??? ??? ??? ?一般情況下,我們一般填0
?? ??? ??? ??? ??? ??? ??? ??? ??? ?即無名信號(hào)量一般我們用于線程間和有親緣關(guān)系的進(jìn)程間。
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?value:指定無名信號(hào)量的初始值
?? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?2.?? ?POSIX信號(hào)量的PV操作
?? ??? ??? ??? ??? ??? ?P操作:sem_wait
?? ??? ??? ??? ??? ??? ?NAME
?? ??? ??? ??? ??? ??? ??? ?sem_wait, sem_timedwait, sem_trywait - lock a semaphore
?? ??? ??? ??? ??? ??? ?SYNOPSIS
?? ??? ??? ??? ??? ??? ??? ?#include <semaphore.h>
?? ??? ??? ??? ??? ??? ??? ?int sem_wait(sem_t *sem);
?? ??? ??? ??? ??? ??? ??? ??? ?此函數(shù)會(huì)阻塞等待--->死等
?? ??? ??? ??? ??? ??? ??? ??? ?sem:要做P操作的信號(hào)量
?? ??? ??? ??? ??? ??? ??? ??? ?返回值:返回0表示獲取到了該信號(hào)量
?? ??? ??? ??? ??? ??? ??? ??? ??? ?返回-1出錯(cuò),同時(shí)errno被設(shè)置
?? ??? ??? ??? ??? ??? ??? ?int sem_trywait(sem_t *sem);
?? ??? ??? ??? ??? ??? ??? ??? ?非阻塞版本-->能獲取則獲取,不能獲取則返回-1
?? ??? ??? ??? ??? ??? ??? ??? ?返回值:返回0,獲取到了該信號(hào)量
?? ??? ??? ??? ??? ??? ??? ??? ??? ?返回-1出錯(cuò),同時(shí)errno被設(shè)置。
?? ??? ??? ??? ??? ??? ??? ?int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
?? ??? ??? ??? ??? ??? ??? ??? ?限時(shí)等待-->等一段時(shí)間后獲取不了,則返回-1
?? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?struct timespec {
?? ??? ??? ??? ??? ??? ??? ??? ??? ?long ? ?tv_sec; ? ? ? ? /* seconds */
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//秒數(shù)
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?long ? ?tv_nsec; ? ? ? ?/* nanoseconds */
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//納秒
?? ??? ??? ??? ??? ??? ??? ??? ?};
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?abs_timeout:指定等待超時(shí)的絕對(duì)時(shí)間
?? ??? ??? ??? ??? ??? ??? ??? ??? ?時(shí)間分為:絕對(duì)時(shí)間和相對(duì)時(shí)間
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?如何去獲取當(dāng)前時(shí)間呢?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?當(dāng)前時(shí)間+相對(duì)時(shí)間=絕對(duì)時(shí)間
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?#include <time.h>
?? ??? ??? ??? ??? ??? ??? ??? ?int clock_gettime(clockid_t clk_id, struct timespec *tp);
?? ??? ??? ??? ??? ??? ??? ??? ??? ?clk_id:CLOCK_REALTIME
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?例子:
?? ??? ??? ??? ??? ??? ??? ??? ??? ?//獲取當(dāng)前時(shí)間保存起來
?? ??? ??? ??? ??? ??? ??? ??? ??? ?struct timespec ts;
?? ??? ??? ??? ??? ??? ??? ??? ??? ?clock_gettime(CLOCK_REALTIME,&ts);
?? ??? ??? ??? ??? ??? ??? ??? ??? ?//假設(shè)我現(xiàn)在想等待15s:30ms
?? ??? ??? ??? ??? ??? ??? ??? ??? ?ts.tv_sec += 15;
?? ??? ??? ??? ??? ??? ??? ??? ??? ?ts.tv_nsec += 30000000;
?? ??? ??? ??? ??? ??? ??? ??? ??? ?if(ts.tv_nsec >= 1000000000)
?? ??? ??? ??? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?ts.tv_sec += 1;
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?ts.tv_nsec -= 1000000000;
?? ??? ??? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ?V操作:sem_post
?? ??? ??? ??? ??? ??? ??? ??? ?sem_post用來釋放sem指定的POSIX信號(hào)量
?? ??? ??? ??? ??? ??? ??? ??? ?#include <semaphore.h>
?? ??? ??? ??? ??? ??? ??? ??? ?int sem_post(sem_t *sem);
?? ??? ??? ??? ??? ??? ??? ??? ?Link with -pthread.
?? ??? ??? ??? ??? ?3.?? ?POSIX信號(hào)量的關(guān)閉和刪除操作
?? ??? ??? ??? ??? ??? ?有名信號(hào)量:
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?#include <semaphore.h>
?? ??? ??? ??? ??? ??? ?int sem_close(sem_t *sem);
?? ??? ??? ??? ??? ??? ?Link with -pthread.?? ?
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?#include <semaphore.h>
?? ??? ??? ??? ??? ??? ?int sem_unlink(const char *name);
?? ??? ??? ??? ??? ??? ??? ?name:要?jiǎng)h除的POSIX有名信號(hào)量的路徑名
?? ??? ??? ??? ??? ??? ??? ?返回值:成功返回0,失敗返回-1,同時(shí)errno被設(shè)置。
?? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?Link with -pthread.
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?無名信號(hào)量:
?? ??? ??? ??? ??? ??? ??? ?sem_destory
?? ??? ??? ??? ??? ??? ??? ?#include <semaphore.h>
?? ??? ??? ??? ??? ??? ??? ?int sem_destroy(sem_t *sem);
?? ??? ??? ??? ??? ??? ??? ?Link with -pthread.
?? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?信號(hào)量一般情況下是用來保護(hù)共享資源的,但是信號(hào)量可以有其他的
?? ??? ??? ??? ??? ??? ?意外的作用,如:
?? ??? ??? ??? ??? ??? ??? ?我們fork一個(gè)子進(jìn)程,想讓子進(jìn)程先執(zhí)行.
?
總結(jié)
- 上一篇: win10多任务分屏快捷键是哪个
- 下一篇: 损友圈在哪下载(损友是什么意思)