1. 程式人生 > >Linux程序間通訊之訊號量(semaphore)、訊息佇列(Message Queue)和共享記憶體(Share Memory)

Linux程序間通訊之訊號量(semaphore)、訊息佇列(Message Queue)和共享記憶體(Share Memory)

System V 程序通訊方式:訊號量(semaphore)、訊息佇列(Message Queue)和共享記憶體(Share Memory)

訊號量

訊號量(semaphore)實際是一個整數,它的值由多個程序進行測試(test)和設定(set)。就每個程序所關心的測試和設定操作而言,這兩個操作是不可中斷的,或稱“原子”操作,即一旦開始直到兩個操作全部完成。測試和設定操作的結果是:訊號量的當前值和設定值相加,其和或者是正或者為負。根據測試和設定操作的結果,一個程序可能必須睡眠,直到有另一個程序改變訊號量的值。

訊號量可用來實現所謂的“臨界區”的互斥使用,臨界區指同一時刻只能有一個程序執行其中程式碼的程式碼段。為了進一步理解訊號量的使用,下面我們舉例說明。

假設你有很多相互協作的程序,它們正在讀或寫一個數據檔案中的記錄。你可能希望嚴格協調對這個檔案的存取,於是你使用初始值為1的訊號量,在這個訊號量上實施兩個操作,首先測試並且給訊號量的值減1,然後測試並給訊號量的值加1。當第一個程序存取檔案時,它把訊號量的值減1,並獲得成功,訊號量的值現在變為0,這個程序可以繼續執行並存取資料檔案。但是,如果另外一個程序也希望存取這個檔案,那麼它也把訊號量的值減1,結果是不能存取這個檔案,因為訊號量的值變為-1。這個程序將被掛起,直到第一個程序完成對資料檔案的存取。當第一個程序完成對資料檔案的存取,它將增加訊號量的值,使它重新變為1,現在,等待的程序被喚醒,它對訊號量的減1操作將獲得成功。

訊息佇列

訊息佇列也稱為報文佇列,訊息佇列是隨核心持續的,只有在核心重起或顯示刪除一個訊息佇列時,該訊息佇列才會真正刪除 系統中記錄訊息佇列的資料結構struct ipc_ids msg_ids位於核心中,系統中所有訊息佇列都可以在結構msg_ids中找到訪問入口

訊息佇列其實就是一個訊息的連結串列,每個訊息佇列有一個佇列頭,稱為struct msg_queue,這個佇列頭描述了訊息佇列的key值,使用者ID,組ID等資訊,但它存於核心中而結構體struct msqid_ds能夠返回或設定訊息佇列的資訊,這個結構體位於使用者空間中,與msg_queue結構相似訊息佇列允許一個或多個程序向它寫入或讀取訊息,訊息佇列是訊息的連結串列。

訊息是按訊息型別訪問,程序必須指定訊息型別來讀取訊息,同樣,當向訊息佇列中寫入訊息時也必須給出訊息的型別,如果讀佇列使用的訊息型別為0,則讀取佇列中的第一條訊息。

核心空間的結構體msg_queue描述了對應key值訊息佇列的情況,而對應於使用者空間的msqid_ds這個結構體,因此,可以操作msgid_ds這個結構體來操作訊息佇列。

共享記憶體

共享記憶體是執行在同一臺機器上的程序間通訊最快的方式,因為資料不需要在不同的程序間複製。通常由一個程序建立一塊共享記憶體區,其餘程序對這塊記憶體區進行讀寫。共享記憶體往往與其它通訊機制,如訊號量結合使用,來達到程序間的同步及互斥。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <error.h>

#define SIZE 1024

int main()
{
    int shmid ;
    char *shmaddr ;
    struct shmid_ds buf ;
    int flag = 0 ;
    int pid ;

    //0(IPC_PRIVATE):會建立新共享記憶體物件,IPC_CREAT與IPC物件存取許可權(如0600)進行|運算來確定訊號量集的存取許可權
    shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0600 ) ;   
    if ( shmid < 0 )
    {
        perror("get shm  ipc_id error") ;
        return -1 ;
    }

    pid = fork() ;
    if ( pid == 0 )
    {
        shmaddr = (char *)shmat( shmid, NULL, 0 ) ;      //直接指定為NULL讓核心自己決定一個合適的地址位置
        if ( (int)shmaddr == -1 )
        {
            perror("shmat addr error") ;
            return -1 ;
        }
        strcpy( shmaddr, "Hi, I am child process!\n") ;

        //與shmat函式相反,shmdt是用來斷開與共享記憶體附加點的地址,禁止本程序訪問此片共享記憶體
        shmdt( shmaddr ) ;                               

        return  0;
    } else if ( pid > 0) {
        sleep(3 ) ;

        //完成對共享記憶體的控制,得到共享記憶體的狀態,把共享記憶體的shmid_ds結構複製到buf中
        flag = shmctl( shmid, IPC_STAT, &buf) ;      
        if ( flag == -1 )
        {
            perror("shmctl shm error") ;
            return -1 ;
        }
        printf("shm_segsz =%d bytes\n", buf.shm_segsz ) ;
        printf("parent pid=%d, shm_cpid = %d \n", getpid(), buf.shm_cpid ) ;
        printf("chlid pid=%d, shm_lpid = %d \n",pid , buf.shm_lpid ) ;

        shmaddr = (char *) shmat(shmid, NULL, 0 ) ;
        if ( (int)shmaddr == -1 )
        {
            perror("shmat addr error") ;
            return -1 ;
        }

        printf("%s", shmaddr) ;
        shmdt( shmaddr ) ;
        shmctl(shmid, IPC_RMID, NULL) ;   //IPC_RMID:刪除這片共享記憶體

    }
    else
    {
        perror("fork error") ;
        shmctl(shmid, IPC_RMID, NULL) ;
    }

    return 0 ;
}


PS:

系統建立IPC通訊(如訊息佇列、共享記憶體時)必須指定一個ID值 。通常情況下,該id值通過ftok函式得到
ftok原型如下:

key_t ftok( char * fname, int id )

引數說明:

                fname就時您指定的文件名            id是子序號。

返回值:

                在一般的UNIX實現中,是將文件的索引節點號取出,前面加上子序號得到key_t的返回值

如指定文件的索引節點號為65538,換算成16進製為0x010002,而您指定的ID值為38,換算成16進位制   為 0x26,則最後的key_t返回值為0x26010002。

(查詢文件索引節點號的方法是: ls -i)

相關推薦

Linux程序通訊訊號(semaphore)訊息佇列(Message Queue)共享記憶體(Share Memory)

System V 程序通訊方式:訊號量(semaphore)、訊息佇列(Message Queue)和共享記憶體(Share Memory) 訊號量 訊號量(semaphore)實際是一個整數,它的值由多個程序進行測試(test)和設定(set)。就每個程序所關心的測試和

linux程序通訊訊號(semaphore)

==================================================== 訊號量(semaphore)簡介 當我們在多使用者系統,多程序系統,或是兩者混合的系統中使用執行緒操作編寫程式時,我們經常會發現我們有段臨界程式碼,在此處我們需要

Linux程序通訊訊號 semget()semop()semctl()

這篇文章將講述別一種程序間通訊的機制——訊號量。注意請不要把它與之前所說的訊號混淆起來,訊號與訊號量是不同的兩種事物。有關訊號的更多內容,可以閱讀我的另一篇文章:Linux程序間通訊 -- 訊號。下面就進入訊號量的講解。 一、什麼是訊號量 為了防止出現

Linux程序通訊訊號通訊

訊號通訊是Linux程序間通訊的一種方式。 1.什麼是訊號? 訊號是系統響應某些條件而產生的一個事件,接收到該訊號的程序會相應地採取一些措施。例如我們在windows系統中想強制結束一個程式我們需要用到的是工作管理員,而在Linux中,我們是通過訊號來實現的,執

linux 程序通訊訊號

Linux訊號(signal) 機制分析 轉載至:https://www.cnblogs.com/hoys/archive/2012/08/19/2646377.html 【摘要】本文分析了Linux核心對於訊號的實現機制和應

Linux程序通訊——使用訊號

這篇文章將講述別一種程序間通訊的機制——訊號量。注意請不要把它與之前所說的訊號混淆起來,訊號與訊號量是不同的兩種事物。有關訊號的更多內容,可以閱讀我的另一篇文章:Linux程序間通訊——使用訊號。下面就進入訊號量的講解。 一、什麼是訊號量 為了防止出現因多個程式同時訪問一

程序通訊訊號

何為訊號量 訊號量的本質是一種資料操作鎖,它本身不具有資料交換的功能,而是通過控制其他的通訊資源(檔案,外部裝置)來實現程序間通訊,它本身只是一種外部資源的標識。訊號量在此過程中負責資料操作的互斥、同步等功能。 對訊號量的操作 當請求一個使用訊號量來表示的資源時,程序需要

程序通訊——訊號(一)(system V)

system v訊號量又被稱為system v訊號量集。它的本質就是一個計數器,用來為多個程序共享的資料結構提供受控訪問。訊號量支援的操作有:使用最廣泛的訊號量為二元訊號量,它控制單個資源,對於這種訊號量而言,它只有兩種合法值: 0 和 1 ,對應一個可用的資源。若當前有資源

程序通訊(IPC)-管道訊息佇列共享記憶體訊號訊號套接字

多程序:首先,先來講一下fork之後,發生了什麼事情。由fork建立的新程序被稱為子程序(child process)。該函式被呼叫一次,但返回兩次。兩次返回的區別是子程序的返回值是0,而父程序的返回值則是新程序(子程序)的程序 id。將子程序id返回給父程序的理由是:因為一

Linux高階程式設計基礎——程序通訊訊號的安裝與傳送

程序間通訊之訊號的安裝與傳送 呼叫setitimer函式分別觸發SIGALRM訊號,SIGVTALRM訊號,SIGPROF訊號 ;(可以由多程序分別觸發每個訊號) 編寫訊號安裝函式,在該函式內部能判斷接受到的是什麼訊號,並把訊號打印出來。 #include

Linux高階程式設計基礎——程序通訊訊號值操作

程序間通訊之訊號值操作 程序A向程序B傳送訊號,該訊號的附帶資訊為一個值為20的整數; 程序B完成接收訊號的功能,並且打印出訊號名稱以及隨著訊號一起傳送過來的整形變數值。 /這個實驗分成兩個小部分。要把這兩個小程式分開執行,在執行這兩個程式之前先在終端上進入

程序通訊方式——訊號Semaphore

1.訊號量 訊號量本質上是一個計數器(不設定全域性變數是因為程序間是相互獨立的,而這不一定能看到,看到也不能保證++引用計數為原子操作),用於多程序對共享資料物件的讀取,它和管道有所不同,它不以傳送資料為主要目的,它主要是用來保護共享資源(訊號量也屬於臨界資源

Linux程序通訊(一)——管道訊號

一、Linux程序間通訊方式 :有六種方式在兩個程式間傳遞資訊         1、訊號( Singal )         2、管道 ( Pipe ) 及有名管道         3、訊號量 (

linux 程序通訊FIFO

1.概述 FIFO與管道幾乎類似,所以FIFO也是一個位元組流,從FIFO讀取的順序也是與被寫入FIFO的順序一致,容量是也有限的,也是可以確保寫入不超過PIPE_BUF位元組的操作是原子的,FIFO的本質也是一個管道,但傳遞方向是可以雙向的,它們兩者之間的最大差別在於FIFO在檔案系統中擁有一個名稱,並且

LinuxLinux程序通訊訊息佇列

1、訊息佇列概念引入    訊息佇列提供了一個從一個程序向另外一個程序傳送一塊資料的方法每個資料塊都被認為是有一個型別,接收者程序接收的資料塊可以有不同的型別值訊息佇列也有管道一樣的不足,就是每個訊息的最大長度是有上限的(MSG

Linux程序通訊pipe

1、管道(PIPE)        從概念上說,管道是兩個程序之間的一個connection,因此一個程序的標準輸出就變成了另一個程序的標準輸入。在Unix作業系統中,管道用於程序間通訊(inter-process communication). (1

Linux程序通訊POSIX訊息佇列

訊息佇列可認為是一個訊息連結串列,它允許程序之間以訊息的形式交換資料。有足夠寫許可權的程序或執行緒可往佇列中放置訊息,有足夠讀許可權的程序或執行緒可從佇列中取走訊息。每個訊息都是一個記錄,它由傳送者賦予一個優先順序。與管道不同,管道是位元組流模型,沒有訊息邊界。

Linux程序通訊——管道(整理)

 程序間通訊 fork pipe pie_t 等用法(管道機制 通訊) 每個程序各自有不同的使用者地址空間,任 何一個程序的全域性變數在另一個程序中都看不到,所以程序之間要交換資料必須通過核心,在核心中開闢一塊緩衝 區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從

Linux程序通訊POSIX共享記憶體

共享記憶體是最高效的IPC機制,因為它不涉及程序之間的任何資料傳輸。這種高效率帶來的問題是,我們必須用其他輔助手段來同步程序對共享記憶體的訪問,否則會產生競態條件。因此,共享記憶體通常和其他程序間通訊方式一起使用。 Linux下有三種共享記憶體的IPC技術:S

Linux -- 程序通訊管道

管道是Linux裡的一種檔案型別,同時也是Linux系統下程序間通訊的一種方式 建立一個管道檔案有兩種方式: 1.  Shell 下命令 mkfifo + filename,即建立一個有名管道 2.