當(dāng)前位置:首頁 > 嵌入式 > 嵌入式軟件
[導(dǎo)讀]進(jìn)程是操作系統(tǒng)的概念,每當(dāng)我們執(zhí)行一個(gè)程序時(shí),對(duì)于操作系統(tǒng)來講就創(chuàng)建了一個(gè)進(jìn)程,在這個(gè)過程中,伴隨著資源的分配和釋放??梢哉J(rèn)為進(jìn)程是一個(gè)程序的一次執(zhí)行過程。

進(jìn)程的概念

· 進(jìn)程是操作系統(tǒng)的概念,每當(dāng)我們執(zhí)行一個(gè)程序時(shí),對(duì)于操作系統(tǒng)來講就創(chuàng)建了一個(gè)進(jìn)程,在這個(gè)過程中,伴隨著資源的分配和釋放。可以認(rèn)為進(jìn)程是一個(gè)程序的一次執(zhí)行過程。

進(jìn)程通信的概念

· 進(jìn)程用戶空間是相互獨(dú)立的,一般而言是不能相互訪問的。但很多情況下進(jìn)程間需要互相通信,來完成系統(tǒng)的某項(xiàng)功能。進(jìn)程通過與內(nèi)核及其它進(jìn)程之間的互相通信來協(xié)調(diào)它們的行為。

進(jìn)程通信的應(yīng)用場景

數(shù)據(jù)傳輸:一個(gè)進(jìn)程需要將它的數(shù)據(jù)發(fā)送給另一個(gè)進(jìn)程,發(fā)送的數(shù)據(jù)量在一個(gè)字節(jié)到幾兆字節(jié)之間。

共享數(shù)據(jù):多個(gè)進(jìn)程想要操作共享數(shù)據(jù),一個(gè)進(jìn)程對(duì)共享數(shù)據(jù)的修改,別的進(jìn)程應(yīng)該立刻看到。

通知事件:一個(gè)進(jìn)程需要向另一個(gè)或一組進(jìn)程發(fā)送消息,通知它(它們)發(fā)生了某種事件(如進(jìn)程終止時(shí)要通知父進(jìn)程)。

資源共享:多個(gè)進(jìn)程之間共享同樣的資源。為了作到這一點(diǎn),需要內(nèi)核提供鎖和同步機(jī)制。

進(jìn)程控制:有些進(jìn)程希望完全控制另一個(gè)進(jìn)程的執(zhí)行(如Debug進(jìn)程),此時(shí)控制進(jìn)程希望能夠攔截另一個(gè)進(jìn)程的所有陷入和異常,并能夠及時(shí)知道它的狀態(tài)改變。

進(jìn)程通信的方式

管道( pipe ):

管道包括三種:

· 普通管道PIPE: 通常有兩種限制,一是單工,只能單向傳輸;二是只能在父子或者兄弟進(jìn)程間使用.

· 流管道s_pipe: 去除了第一種限制,為半雙工,只能在父子或兄弟進(jìn)程間使用,可以雙向傳輸.

· 命名管道:name_pipe:去除了第二種限制,可以在許多并不相關(guān)的進(jìn)程之間進(jìn)行通訊.

信號(hào)量( semophore ) :

· 信號(hào)量是一個(gè)計(jì)數(shù)器,可以用來控制多個(gè)進(jìn)程對(duì)共享資源的訪問。它常作為一種鎖機(jī)制,防止某進(jìn)程正在訪問共享資源時(shí),其他進(jìn)程也訪問該資源。因此,主要作為進(jìn)程間以及同一進(jìn)程內(nèi)不同線程之間的同步手段。

消息隊(duì)列( message queue ) :

· 消息隊(duì)列是由消息的鏈表,存放在內(nèi)核中并由消息隊(duì)列標(biāo)識(shí)符標(biāo)識(shí)。消息隊(duì)列克服了信號(hào)傳遞信息少、管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等缺點(diǎn)。

信號(hào) ( sinal ) :

· 信號(hào)是一種比較復(fù)雜的通信方式,用于通知接收進(jìn)程某個(gè)事件已經(jīng)發(fā)生。

共享內(nèi)存( shared memory ) :

· 共享內(nèi)存就是映射一段能被其他進(jìn)程所訪問的內(nèi)存,這段共享內(nèi)存由一個(gè)進(jìn)程創(chuàng)建,但多個(gè)進(jìn)程都可以訪問。共享內(nèi)存是最快的 IPC 方式,它是針對(duì)其他進(jìn)程間通信方式運(yùn)行效率低而專門設(shè)計(jì)的。它往往與其他通信機(jī)制,如信號(hào)兩,配合使用,來實(shí)現(xiàn)進(jìn)程間的同步和通信。

套接字( socket ) :

· 套解口也是一種進(jìn)程間通信機(jī)制,與其他通信機(jī)制不同的是,它可用于不同機(jī)器間的進(jìn)程通信。

各進(jìn)程間通信的原理

管道

管道是如何通信的

管道是由內(nèi)核管理的一個(gè)緩沖區(qū),相當(dāng)于我們放入內(nèi)存中的一個(gè)紙條。管道的一端連接一個(gè)進(jìn)程的輸出。這個(gè)進(jìn)程會(huì)向管道中放入信息。管道的另一端連接一個(gè)進(jìn)程的輸入,這個(gè)進(jìn)程取出被放入管道的信息。一個(gè)緩沖區(qū)不需要很大,它被設(shè)計(jì)成為環(huán)形的數(shù)據(jù)結(jié)構(gòu),以便管道可以被循環(huán)利用。當(dāng)管道中沒有信息的話,從管道中讀取的進(jìn)程會(huì)等待,直到另一端的進(jìn)程放入信息。當(dāng)管道被放滿信息的時(shí)候,嘗試放入信息的進(jìn)程會(huì)等待,直到另一端的進(jìn)程取出信息。當(dāng)兩個(gè)進(jìn)程都終結(jié)的時(shí)候,管道也自動(dòng)消失。

管道是如何創(chuàng)建的

從原理上,管道利用fork機(jī)制建立,從而讓兩個(gè)進(jìn)程可以連接到同一個(gè)PIPE上。最開始的時(shí)候,上面的兩個(gè)箭頭都連接在同一個(gè)進(jìn)程Process 1上(連接在Process 1上的兩個(gè)箭頭)。當(dāng)fork復(fù)制進(jìn)程的時(shí)候,會(huì)將這兩個(gè)連接也復(fù)制到新的進(jìn)程(Process 2)。隨后,每個(gè)進(jìn)程關(guān)閉自己不需要的一個(gè)連接 (兩個(gè)黑色的箭頭被關(guān)閉; Process 1關(guān)閉從PIPE來的輸入連接,Process 2關(guān)閉輸出到PIPE的連接),這樣,剩下的紅色連接就構(gòu)成了如上圖的PIPE。

· 管道通信的實(shí)現(xiàn)細(xì)節(jié)

在 Linux 中,管道的實(shí)現(xiàn)并沒有使用專門的數(shù)據(jù)結(jié)構(gòu),而是借助了文件系統(tǒng)的file結(jié)構(gòu)和VFS的索引節(jié)點(diǎn)inode。通過將兩個(gè) file 結(jié)構(gòu)指向同一個(gè)臨時(shí)的 VFS 索引節(jié)點(diǎn),而這個(gè) VFS 索引節(jié)點(diǎn)又指向一個(gè)物理頁面而實(shí)現(xiàn)的。如下圖

有兩個(gè) file 數(shù)據(jù)結(jié)構(gòu),但它們定義文件操作進(jìn)程地址是不同的,其中一個(gè)是向管道中寫入數(shù)據(jù)的進(jìn)程地址,而另一個(gè)是從管道中讀出數(shù)據(jù)的進(jìn)程地址。這樣,用戶程序的系統(tǒng)調(diào)用仍然是通常的文件操作,而內(nèi)核卻利用這種抽象機(jī)制實(shí)現(xiàn)了管道這一特殊操作。

關(guān)于管道的讀寫

管道實(shí)現(xiàn)的源代碼在fs/pipe.c中,在pipe.c中有很多函數(shù),其中有兩個(gè)函數(shù)比較重要,即管道讀函數(shù)pipe_read()和管道寫函數(shù)pipe_wrtie()。管道寫函數(shù)通過將字節(jié)復(fù)制到 VFS 索引節(jié)點(diǎn)指向的物理內(nèi)存而寫入數(shù)據(jù),而管道讀函數(shù)則通過復(fù)制物理內(nèi)存中的字節(jié)而讀出數(shù)據(jù)。當(dāng)然,內(nèi)核必須利用一定的機(jī)制同步對(duì)管道的訪問,為此,內(nèi)核使用了鎖、等待隊(duì)列和信號(hào)。

當(dāng)寫進(jìn)程向管道中寫入時(shí),它利用標(biāo)準(zhǔn)的庫函數(shù)write(),系統(tǒng)根據(jù)庫函數(shù)傳遞的文件描述符,可找到該文件的 file 結(jié)構(gòu)。file 結(jié)構(gòu)中指定了用來進(jìn)行寫操作的函數(shù)(即寫入函數(shù))地址,于是,內(nèi)核調(diào)用該函數(shù)完成寫操作。寫入函數(shù)在向內(nèi)存中寫入數(shù)據(jù)之前,必須首先檢查 VFS 索引節(jié)點(diǎn)中的信息,同時(shí)滿足如下條件時(shí),才能進(jìn)行實(shí)際的內(nèi)存復(fù)制工作:

· 內(nèi)存中有足夠的空間可容納所有要寫入的數(shù)據(jù);

· 內(nèi)存沒有被讀程序鎖定。

如果同時(shí)滿足上述條件,寫入函數(shù)首先鎖定內(nèi)存,然后從寫進(jìn)程的地址空間中復(fù)制數(shù)據(jù)到內(nèi)存。否則,寫入進(jìn)程就休眠在 VFS 索引節(jié)點(diǎn)的等待隊(duì)列中,接下來,內(nèi)核將調(diào)用調(diào)度程序,而調(diào)度程序會(huì)選擇其他進(jìn)程運(yùn)行。寫入進(jìn)程實(shí)際處于可中斷的等待狀態(tài),當(dāng)內(nèi)存中有足夠的空間可以容納寫入數(shù)據(jù),或內(nèi)存被解鎖時(shí),讀取進(jìn)程會(huì)喚醒寫入進(jìn)程,這時(shí),寫入進(jìn)程將接收到信號(hào)。當(dāng)數(shù)據(jù)寫入內(nèi)存之后,內(nèi)存被解鎖,而所有休眠在索引節(jié)點(diǎn)的讀取進(jìn)程會(huì)被喚醒。

管道的讀取過程和寫入過程類似。但是,進(jìn)程可以在沒有數(shù)據(jù)或內(nèi)存被鎖定時(shí)立即返回錯(cuò)誤信息,而不是阻塞該進(jìn)程,這依賴于文件或管道的打開模式。反之,進(jìn)程可以休眠在索引節(jié)點(diǎn)的等待隊(duì)列中等待寫入進(jìn)程寫入數(shù)據(jù)。當(dāng)所有的進(jìn)程完成了管道操作之后,管道的索引節(jié)點(diǎn)被丟棄,而共享數(shù)據(jù)頁也被釋放。

Linux函數(shù)原型

#include

int pipe(int filedes[2]);

filedes[0]用于讀出數(shù)據(jù),讀取時(shí)必須關(guān)閉寫入端,即close(filedes[1]);

filedes[1]用于寫入數(shù)據(jù),寫入時(shí)必須關(guān)閉讀取端,即close(filedes[0])。

程序?qū)嵗?/p>

int main(void)

{

int n;

int fd[2];

pid_t pid;

char line[MAXLINE];

if(pipe(fd) 0){ /* 先建立管道得到一對(duì)文件描述符 */

exit(0);

}

if((pid = fork()) 0) /* 父進(jìn)程把文件描述符復(fù)制給子進(jìn)程 */

exit(1);

else if(pid > 0){ /* 父進(jìn)程寫 */

close(fd[0]); /* 關(guān)閉讀描述符 */

write(fd[1], "nhello worldn", 14);

}

else{ /* 子進(jìn)程讀 */

close(fd[1]); /* 關(guān)閉寫端 */

n = read(fd[0], line, MAXLINE);

write(STDOUT_FILENO, line, n);

}

exit(0);

}

命名管道

由于基于fork機(jī)制,所以管道只能用于父進(jìn)程和子進(jìn)程之間,或者擁有相同祖先的兩個(gè)子進(jìn)程之間 (有親緣關(guān)系的進(jìn)程之間)。為了解決這一問題,Linux提供了FIFO方式連接進(jìn)程。FIFO又叫做命名管道(named PIPE)。

實(shí)現(xiàn)原理

FIFO (First in, First out)為一種特殊的文件類型,它在文件系統(tǒng)中有對(duì)應(yīng)的路徑。當(dāng)一個(gè)進(jìn)程以讀(r)的方式打開該文件,而另一個(gè)進(jìn)程以寫(w)的方式打開該文件,那么內(nèi)核就會(huì)在這兩個(gè)進(jìn)程之間建立管道,所以FIFO實(shí)際上也由內(nèi)核管理,不與硬盤打交道。之所以叫FIFO,是因?yàn)楣艿辣举|(zhì)上是一個(gè)先進(jìn)先出的隊(duì)列數(shù)據(jù)結(jié)構(gòu),最早放入的數(shù)據(jù)被最先讀出來,從而保證信息交流的順序。FIFO只是借用了文件系統(tǒng)(file system,命名管道是一種特殊類型的文件,因?yàn)長inux中所有事物都是文件,它在文件系統(tǒng)中以文件名的形式存在。)來為管道命名。寫模式的進(jìn)程向FIFO文件中寫入,而讀模式的進(jìn)程從FIFO文件中讀出。當(dāng)刪除FIFO文件時(shí),管道連接也隨之消失。FIFO的好處在于我們可以通過文件的路徑來識(shí)別管道,從而讓沒有親緣關(guān)系的進(jìn)程之間建立連接

函數(shù)原型:

#include #include

int mkfifo(const char *filename, mode_t mode);int mknode(const char *filename, mode_t mode | S_IFIFO, (dev_t) 0 );

其中filename是被創(chuàng)建的文件名稱,mode表示將在該文件上設(shè)置的權(quán)限位和將被創(chuàng)建的文件類型(在此情況下為S_IFIFO),dev是當(dāng)創(chuàng)建設(shè)備特殊文件時(shí)使用的一個(gè)值。因此,對(duì)于先進(jìn)先出文件它的值為0。

程序?qū)嵗?/p>

#include #include #include #include

int main()

{

int res = mkfifo("/tmp/my_fifo", 0777);

if (res == 0)

{

printf("FIFO created/n");

}

exit(EXIT_SUCCESS);

}

信號(hào)量

什么是信號(hào)量

為了防止出現(xiàn)因多個(gè)程序同時(shí)訪問一個(gè)共享資源而引發(fā)的一系列問題,我們需要一種方法。比如在任一時(shí)刻只能有一個(gè)執(zhí)行線程訪問代碼的臨界區(qū)域。臨界區(qū)域是指執(zhí)行數(shù)據(jù)更新的代碼需要獨(dú)占式地執(zhí)行。而信號(hào)量就可以提供這樣的一種訪問機(jī)制,讓一個(gè)臨界區(qū)同一時(shí)間只有一個(gè)線程在訪問它,也就是說信號(hào)量是用來調(diào)協(xié)進(jìn)程對(duì)共享資源的訪問的。

信號(hào)量是一個(gè)特殊的變量,程序?qū)ζ湓L問都是原子操作,且只允許對(duì)它進(jìn)行等待(即P(信號(hào)變量))和發(fā)送(即V(信號(hào)變量))信息操作。最簡單的信號(hào)量是只能取0和1的變量,這也是信號(hào)量最常見的一種形式,叫做二進(jìn)制信號(hào)量。而可以取多個(gè)正整數(shù)的信號(hào)量被稱為通用信號(hào)量。

信號(hào)量的工作原理

由于信號(hào)量只能進(jìn)行兩種操作等待和發(fā)送信號(hào),即P(sv)和V(sv),他們的行為是這樣的:

· P(sv):如果sv的值大于零,就給它減1;如果它的值為零,就掛起該進(jìn)程的執(zhí)行

· V(sv):如果有其他進(jìn)程因等待sv而被掛起,就讓它恢復(fù)運(yùn)行,如果沒有進(jìn)程因等待sv而掛起,就給它加1.

舉個(gè)例子,就是兩個(gè)進(jìn)程共享信號(hào)量sv,一旦其中一個(gè)進(jìn)程執(zhí)行了P(sv)操作,它將得到信號(hào)量,并可以進(jìn)入臨界區(qū),使sv減1。而第二個(gè)進(jìn)程將被阻止進(jìn)入臨界區(qū),因?yàn)楫?dāng)它試圖執(zhí)行P(sv)時(shí),sv為0,它會(huì)被掛起以等待第一個(gè)進(jìn)程離開臨界區(qū)域并執(zhí)行V(sv)釋放信號(hào)量,這時(shí)第二個(gè)進(jìn)程就可以恢復(fù)執(zhí)行。

Linux的信號(hào)量機(jī)制

Linux提供了一組精心設(shè)計(jì)的信號(hào)量接口來對(duì)信號(hào)進(jìn)行操作,它們不只是針對(duì)二進(jìn)制信號(hào)量,下面將會(huì)對(duì)這些函數(shù)進(jìn)行介紹,但請(qǐng)注意,這些函數(shù)都是用來對(duì)成組的信號(hào)量值進(jìn)行操作的。它們聲明在頭文件sys/sem.h中。

semget函數(shù)

它的作用是創(chuàng)建一個(gè)新信號(hào)量或取得一個(gè)已有信號(hào)量,原型為:

int semget(key_t key, int num_sems, int sem_flags);

第一個(gè)參數(shù)key是整數(shù)值(唯一非零),不相關(guān)的進(jìn)程可以通過它訪問一個(gè)信號(hào)量,它代表程序可能要使用的某個(gè)資源,程序?qū)λ行盘?hào)量的訪問都是間接的,程序先通過調(diào)用semget函數(shù)并提供一個(gè)鍵,再由系統(tǒng)生成一個(gè)相應(yīng)的信號(hào)標(biāo)識(shí)符(semget函數(shù)的返回值),只有semget函數(shù)才直接使用信號(hào)量鍵,所有其他的信號(hào)量函數(shù)使用由semget函數(shù)返回的信號(hào)量標(biāo)識(shí)符。如果多個(gè)程序使用相同的key值,key將負(fù)責(zé)協(xié)調(diào)工作。

第二個(gè)參數(shù)num_sems指定需要的信號(hào)量數(shù)目,它的值幾乎總是1。

第三個(gè)參數(shù)sem_flags是一組標(biāo)志,當(dāng)想要當(dāng)信號(hào)量不存在時(shí)創(chuàng)建一個(gè)新的信號(hào)量,可以和值IPC_CREAT做按位或操作。設(shè)置了IPC_CREAT標(biāo)志后,即使給出的鍵是一個(gè)已有信號(hào)量的鍵,也不會(huì)產(chǎn)生錯(cuò)誤。而IPC_CREAT | IPC_EXCL則可以創(chuàng)建一個(gè)新的,唯一的信號(hào)量,如果信號(hào)量已存在,返回一個(gè)錯(cuò)誤。

semget函數(shù)成功返回一個(gè)相應(yīng)信號(hào)標(biāo)識(shí)符(非零),失敗返回-1.

semop函數(shù)

它的作用是改變信號(hào)量的值,原型為:

int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);

· 1

sem_id是由semget返回的信號(hào)量標(biāo)識(shí)符,sembuf結(jié)構(gòu)的定義如下:

struct sembuf{

short sem_num;//除非使用一組信號(hào)量,否則它為0

short sem_op;//信號(hào)量在一次操作中需要改變的數(shù)據(jù),通常是兩個(gè)數(shù),一個(gè)是-1,即P(等待)操作,

//一個(gè)是+1,即V(發(fā)送信號(hào))操作。

short sem_flg;//通常為SEM_UNDO,使操作系統(tǒng)跟蹤信號(hào),

//并在進(jìn)程沒有釋放該信號(hào)量而終止時(shí),操作系統(tǒng)釋放信號(hào)量

};

semctl函數(shù)

int semctl(int sem_id, int sem_num, int command, ...);

· 1

如果有第四個(gè)參數(shù),它通常是一個(gè)union semum結(jié)構(gòu),定義如下:

union semun{

int val;

struct semid_ds *buf;

unsigned short *arry;

};

前兩個(gè)參數(shù)與前面一個(gè)函數(shù)中的一樣,command通常是下面兩個(gè)值中的其中一個(gè)

SETVAL:用來把信號(hào)量初始化為一個(gè)已知的值。p 這個(gè)值通過union semun中的val成員設(shè)置,其作用是在信號(hào)量第一次使用前對(duì)它進(jìn)行設(shè)置。

IPC_RMID:用于刪除一個(gè)已經(jīng)無需繼續(xù)使用的信號(hào)量標(biāo)識(shí)符。

消息隊(duì)列

什么是消息隊(duì)列

消息隊(duì)列是消息的鏈接表,包括Posix消息隊(duì)列system V消息隊(duì)列。有足夠權(quán)限的進(jìn)程可以向隊(duì)列中添加消息,被賦予讀權(quán)限的進(jìn)程則可以讀走隊(duì)列中的消息。消息隊(duì)列克服了信號(hào)承載信息量少,管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等缺點(diǎn)。消息隊(duì)列是隨內(nèi)核持續(xù)的。

每個(gè)消息隊(duì)列都有一個(gè)隊(duì)列頭,用結(jié)構(gòu)struct msg_queue來描述。隊(duì)列頭中包含了該消息隊(duì)列的大量信息,包括消息隊(duì)列鍵值、用戶ID、組ID、消息隊(duì)列中消息數(shù)目等等,甚至記錄了最近對(duì)消息隊(duì)列讀寫進(jìn)程的ID。讀者可以訪問這些信息,也可以設(shè)置其中的某些信息。

結(jié)構(gòu)msg_queue用來描述消息隊(duì)列頭,存在于系統(tǒng)空間:

struct msg_queue {

struct kern_ipc_perm q_perm;

time_t q_stime; /* last msgsnd time */

time_t q_rtime; /* last msgrcv time */

time_t q_ctime; /* last change time */

unsigned long q_cbytes; /* current number of bytes on queue */

unsigned long q_qnum; /* number of messages in queue */

unsigned long q_qbytes; /* max number of bytes on queue */

pid_t q_lspid; /* pid of last msgsnd */

pid_t q_lrpid; /* last receive pid */

struct list_head q_messages;

struct list_head q_receivers;

struct list_head q_senders;

};

結(jié)構(gòu)msqid_ds用來設(shè)置或返回消息隊(duì)列的信息,存在于用戶空間:

struct msqid_ds {

struct ipc_perm msg_perm;

struct msg *msg_first; /* first message on queue,unused */

struct msg *msg_last; /* last message in queue,unused */

__kernel_time_t msg_stime; /* last msgsnd time */

__kernel_time_t msg_rtime; /* last msgrcv time */

__kernel_time_t msg_ctime; /* last change time */

unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */

unsigned long msg_lqbytes; /* ditto */

unsigned short msg_cbytes; /* current number of bytes on queue */

unsigned short msg_qnum; /* number of messages in queue */

unsigned short msg_qbytes; /* max number of bytes on queue */

__kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */

__kernel_ipc_pid_t msg_lrpid; /* last receive pid */

};

消息隊(duì)列與內(nèi)核的聯(lián)系

下圖說明了內(nèi)核與消息隊(duì)列是怎樣建立起聯(lián)系的:

從上圖可以看出,全局?jǐn)?shù)據(jù)結(jié)構(gòu) struct ipc_ids msg_ids 可以訪問到每個(gè)消息隊(duì)列頭的第一個(gè)成員:struct kern_ipc_perm;而每個(gè)struct kern_ipc_perm能夠與具體的消息隊(duì)列對(duì)應(yīng)起來是因?yàn)樵谠摻Y(jié)構(gòu)中,有一個(gè)key_t類型成員key,而key則唯一確定一個(gè)消息隊(duì)列。 kern_ipc_perm結(jié)構(gòu)如下:

struct kern_ipc_perm{ //內(nèi)核中記錄消息隊(duì)列的全局?jǐn)?shù)據(jù)結(jié)構(gòu)msg_ids能夠訪問到該結(jié)構(gòu);

key_t key; //該鍵值則唯一對(duì)應(yīng)一個(gè)消息隊(duì)列

uid_t uid;

gid_t gid;

uid_t cuid;

gid_t cgid;

mode_t mode;unsigned long seq;

}

消息隊(duì)列的操作

打開或創(chuàng)建消息隊(duì)列

息隊(duì)列的內(nèi)核持續(xù)性要求每個(gè)消息隊(duì)列都在系統(tǒng)范圍內(nèi)對(duì)應(yīng)唯一的鍵值,所以,要獲得一個(gè)消息隊(duì)列的描述字,只需提供該消息隊(duì)列的鍵值即可;

注:消息隊(duì)列描述字是由在系統(tǒng)范圍內(nèi)唯一的鍵值生成的,而鍵值可以看作對(duì)應(yīng)系統(tǒng)內(nèi)的一條路經(jīng)。

讀寫的操作

消息讀寫操作非常簡單,對(duì)開發(fā)人員來說,每個(gè)消息都類似如下的數(shù)據(jù)結(jié)構(gòu):

struct msgbuf{long mtype;char mtext[1];

};

mtype成員代表消息類型,從消息隊(duì)列中讀取消息的一個(gè)重要依據(jù)就是消息的類型;mtext是消息內(nèi)容,當(dāng)然長度不一定為1。因此,對(duì)于發(fā)送消息來說, 首先預(yù)置一個(gè)msgbuf緩沖區(qū)并寫入消息類型和內(nèi)容,調(diào)用相應(yīng)的發(fā)送函數(shù)即可;對(duì)讀取消息來說,首先分配這樣一個(gè)msgbuf緩沖區(qū),然后把消息讀入該緩沖區(qū)即可。

· 獲得或設(shè)置消息隊(duì)列屬性:

消息隊(duì)列的信息基本上都保存在消息隊(duì)列頭中,因此,可以分配一個(gè)類似于消息隊(duì)列頭的結(jié)構(gòu),來返回消息隊(duì)列的屬性;同樣可以設(shè)置該數(shù)據(jù)結(jié)構(gòu)。

信號(hào)

信號(hào)本質(zhì)

· 信號(hào)是在軟件層次上對(duì)中斷機(jī)制的一種模擬,在原理上,一個(gè)進(jìn)程收到一個(gè)信號(hào)與處理器收到一個(gè)中斷請(qǐng)求可以說是一樣的。信號(hào)是異步的,一個(gè)進(jìn)程不必通過任何操作來等待信號(hào)的到達(dá),事實(shí)上,進(jìn)程也不知道信號(hào)到底什么時(shí)候到達(dá)。

· 信號(hào)是進(jìn)程間通信機(jī)制中唯一的異步通信機(jī)制,可以看作是異步通知,通知接收信號(hào)的進(jìn)程有哪些事情發(fā)生了。信號(hào)機(jī)制經(jīng)過POSIX實(shí)時(shí)擴(kuò)展后,功能更加強(qiáng)大,除了基本通知功能外,還可以傳遞附加信息。

信號(hào)來源

信號(hào)事件的發(fā)生有兩個(gè)來源:硬件來源(比如我們按下了鍵盤或者其它硬件故障);軟件來源,最常用發(fā)送信號(hào)的系統(tǒng)函數(shù)是kill, raise, alarm和setitimer以及sigqueue函數(shù),軟件來源還包括一些非法運(yùn)算等操作。

信號(hào)的種類

· 可以從兩個(gè)不同的分類角度對(duì)信號(hào)進(jìn)行分類:(1)可靠性方面:可靠信號(hào)與不可靠信號(hào);(2)與時(shí)間的關(guān)系上:實(shí)時(shí)信號(hào)與非實(shí)時(shí)信號(hào)。

可靠信號(hào)和不可靠信號(hào)

不可靠信號(hào)

Linux信號(hào)機(jī)制基本上是從Unix系統(tǒng)中繼承過來的。早期Unix系統(tǒng)中的信號(hào)機(jī)制比較簡單和原始,后來在實(shí)踐中暴露出一些問題,因此,把那些建立在早期機(jī)制上的信號(hào)叫做”不可靠信號(hào)”,信號(hào)值小于SIGRTMIN(Red hat 7.2中,SIGRTMIN=32,SIGRTMAX=63)的信號(hào)都是不可靠信號(hào)。這就是”不可靠信號(hào)”的來源。它的主要問題是:

· 進(jìn)程每次處理信號(hào)后,就將對(duì)信號(hào)的響應(yīng)設(shè)置為默認(rèn)動(dòng)作。在某些情況下,將導(dǎo)致對(duì)信號(hào)的錯(cuò)誤處理;因此,用戶如果不希望這樣的操作,那么就要在信號(hào)處理函數(shù)結(jié)尾再一次調(diào)用signal(),重新安裝該信號(hào)。

·信號(hào)可能丟失

因此,早期unix下的不可靠信號(hào)主要指的是進(jìn)程可能對(duì)信號(hào)做出錯(cuò)誤的反應(yīng)以及信號(hào)可能丟失。

Linux支持不可靠信號(hào),但是對(duì)不可靠信號(hào)機(jī)制做了改進(jìn):在調(diào)用完信號(hào)處理函數(shù)后,不必重新調(diào)用該信號(hào)的安裝函數(shù)(信號(hào)安裝函數(shù)是在可靠機(jī)制上的實(shí)現(xiàn))。因此,Linux下的不可靠信號(hào)問題主要指的是信號(hào)可能丟失。

可靠信號(hào)

· 隨著時(shí)間的發(fā)展,實(shí)踐證明了有必要對(duì)信號(hào)的原始機(jī)制加以改進(jìn)和擴(kuò)充,力圖實(shí)現(xiàn)”可靠信號(hào)”。由于原來定義的信號(hào)已有許多應(yīng)用,不好再做改動(dòng),最終只好又新增加了一些信號(hào),并在一開始就把它們定義為可靠信號(hào),這些信號(hào)支持排隊(duì),不會(huì)丟失。

· 信號(hào)值位于SIGRTMIN和SIGRTMAX之間的信號(hào)都是可靠信號(hào),可靠信號(hào)克服了信號(hào)可能丟失的問題。Linux在支持新版本的信號(hào)安裝函數(shù)sigation()以及信號(hào)發(fā)送函數(shù)sigqueue()的同時(shí),仍然支持早期的signal()信號(hào)安裝函數(shù),支持信號(hào)發(fā)送函數(shù)kill()

注意:可靠信號(hào)是指后來添加的新信號(hào)(信號(hào)值位于SIGRTMIN及SIGRTMAX之間);不可靠信號(hào)是信號(hào)值小于SIGRTMIN的信號(hào)。信號(hào)的可靠與不可靠只與信號(hào)值有關(guān),與信號(hào)的發(fā)送及安裝函數(shù)無關(guān)。

實(shí)時(shí)信號(hào)與非實(shí)時(shí)信號(hào)

· 非實(shí)時(shí)信號(hào)都不支持排隊(duì),都是不可靠信號(hào),編號(hào)是1-31,0是空信號(hào);實(shí)時(shí)信號(hào)都支持排隊(duì),都是可靠信號(hào)。

進(jìn)程對(duì)信號(hào)的響應(yīng)

· 忽略信號(hào),即對(duì)信號(hào)不做任何處理,其中,有兩個(gè)信號(hào)不能忽略:SIGKILL及SIGSTOP;

· 捕捉信號(hào)。定義信號(hào)處理函數(shù),當(dāng)信號(hào)發(fā)生時(shí),執(zhí)行相應(yīng)的處理函數(shù);

· 執(zhí)行缺省操作,Linux對(duì)每種信號(hào)都規(guī)定了默認(rèn)操作

注意:進(jìn)程對(duì)實(shí)時(shí)信號(hào)的缺省反應(yīng)是進(jìn)程終止。

信號(hào)的發(fā)送和安裝

· 發(fā)送信號(hào)的主要函數(shù)有:kill()、raise()、 sigqueue()、alarm()、setitimer()以及abort()。

· 如果進(jìn)程要處理某一信號(hào),那么就要在進(jìn)程中安裝該信號(hào)。安裝信號(hào)主要用來確定信號(hào)值及進(jìn)程針對(duì)該信號(hào)值的動(dòng)作之間的映射關(guān)系,即進(jìn)程將要處理哪個(gè)信號(hào);該信號(hào)被傳遞給進(jìn)程時(shí),將執(zhí)行何種操作。

注意: inux主要有兩個(gè)函數(shù)實(shí)現(xiàn)信號(hào)的安裝:signal()、sigaction()。其中signal()在可靠信號(hào)系統(tǒng)調(diào)用的基礎(chǔ)上實(shí)現(xiàn), 是庫函數(shù)。它只有兩個(gè)參數(shù),不支持信號(hào)傳遞信息,主要是用于前32種非實(shí)時(shí)信號(hào)的安裝;而sigaction()是較新的函數(shù)(由兩個(gè)系統(tǒng)調(diào)用實(shí)現(xiàn):sys_signal以及sys_rt_sigaction),有三個(gè)參數(shù),支持信號(hào)傳遞信息,主要用來與 sigqueue() 系統(tǒng)調(diào)用配合使用,當(dāng)然,sigaction()同樣支持非實(shí)時(shí)信號(hào)的安裝。sigaction()優(yōu)于signal()主要體現(xiàn)在支持信號(hào)帶有參數(shù)。

共享內(nèi)存

共享內(nèi)存可以說是最有用的進(jìn)程間通信方式,也是最快的IPC形式。是針對(duì)其他通信機(jī)制運(yùn)行效率較低而設(shè)計(jì)的。兩個(gè)不同進(jìn)程A、B共享內(nèi)存的意思是,同一塊物理內(nèi)存被映射到進(jìn)程A、B各自的進(jìn)程地址空間。進(jìn)程A可以即時(shí)看到進(jìn)程B對(duì)共享內(nèi)存中數(shù)據(jù)的更新,反之亦然。由于多個(gè)進(jìn)程共享同一塊內(nèi)存區(qū)域,必然需要某種同步機(jī)制,互斥鎖和信號(hào)量都可以。

系統(tǒng)V共享內(nèi)存原理

進(jìn)程間需要共享的數(shù)據(jù)被放在一個(gè)叫做IPC共享內(nèi)存區(qū)域的地方,所有需要訪問該共享區(qū)域的進(jìn)程都要把該共享區(qū)域映射到本進(jìn)程的地址空間中去。系統(tǒng)V共享內(nèi)存通過shmget獲得或創(chuàng)建一個(gè)IPC共享內(nèi)存區(qū)域,并返回相應(yīng)的標(biāo)識(shí)符。內(nèi)核在保證shmget獲得或創(chuàng)建一個(gè)共享內(nèi)存區(qū),初始化該共享內(nèi)存區(qū)相應(yīng)的shmid_kernel結(jié)構(gòu)體的同時(shí),還將在特殊文件系統(tǒng)shm中,創(chuàng)建并打開一個(gè)同名文件,并在內(nèi)存中建立起該文件的相應(yīng)dentry及inode結(jié)構(gòu),新打開的文件不屬于任何一個(gè)進(jìn)程(任何進(jìn)程都可以訪問該共享內(nèi)存區(qū))。所有這一切都是系統(tǒng)調(diào)用shmget完成的。

系統(tǒng)V共享內(nèi)存API

shmget()用來獲得共享內(nèi)存區(qū)域的ID,如果不存在指定的共享區(qū)域就創(chuàng)建相應(yīng)的區(qū)域。shmat()把共享內(nèi)存區(qū)域映射到調(diào)用進(jìn)程的地址空間中去,這樣,進(jìn)程就可以方便地對(duì)共享區(qū)域進(jìn)行訪問操作。shmdt()調(diào)用用來解除進(jìn)程對(duì)共享內(nèi)存區(qū)域的映射。shmctl實(shí)現(xiàn)對(duì)共享內(nèi)存區(qū)域的控制操作。

套接字(socket)

最早出現(xiàn)在UNIX系統(tǒng)中,是UNIX系統(tǒng)主要的信息傳遞方式。

Socket相關(guān)概念

兩個(gè)基本概念:客戶方和服務(wù)方。當(dāng)兩個(gè)應(yīng)用之間需要采用SOCKET通信時(shí),首先需要在兩個(gè)應(yīng)用之間(可能位于同一臺(tái)機(jī)器,也可能位于不同的機(jī)器)建立SOCKET連接。

發(fā)起呼叫連接請(qǐng)求的一方為客戶方

在客戶方呼叫連接請(qǐng)求之前,它必須知道服務(wù)方在哪里。所以需要知道服務(wù)方所在機(jī)器的IP地址或機(jī)器名稱,如果客戶方和服務(wù)方事前有一個(gè)約定就好了,這個(gè)約定就是PORT(端口號(hào))。也就是說,客戶方可以通過服務(wù)方所在機(jī)器的IP地址或機(jī)器名稱和端口號(hào)唯一的確定方式來呼叫服務(wù)方。

接受呼叫連接請(qǐng)求的一方成為服務(wù)方。

在客戶方呼叫之前,服務(wù)方必須處于偵聽狀態(tài),偵聽是否有客戶要求建立連接。一旦接到連接請(qǐng)求,服務(wù)方可以根據(jù)情況建立或拒絕連接。當(dāng)客戶方的消息到達(dá)服務(wù)方端口時(shí),會(huì)自動(dòng)觸發(fā)一個(gè)事件(event),服務(wù)方只要接管該事件,就可以接受來自客戶方的消息了。

Socket類型

· 流式Socket(STREAM):是一種面向連接的Socekt,針對(duì)面向連接的TCP服務(wù)應(yīng)用,安全,但是效率低;

· 數(shù)據(jù)報(bào)式Socket(DATAGAM):是一種無連接的Socket,對(duì)應(yīng)于無連接的UDP服務(wù)應(yīng)用。不安(丟失,順序混亂,在接受端要分析重排及要求重發(fā)),但效率高。

Socket一般應(yīng)用模式(服務(wù)端和客戶端)

Socket通信基本流程圖

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉