Linux 進程通訊(共享內存區)

共享內存是由內核出於在多個進程間交換信息的目的而留出的一塊內存區(段)。
若是段的權限設置恰當,每一個要訪問該段內存的進程均可以把它映像到本身的私有地址空間中。
若是一個進程更新了段中的數據,其餘進程也當即會看到更新。
由一個進程建立的段,也能夠由另外一個進程讀寫。
每一個進程都把它本身對共享內存的映像放入本身的地址空間。
建立共享內存區
int shmget(key_t key,size_t size,int shm-flg);
參數key既能夠是IPC_PRIVATE(IPC_PRIVATE表示讓系統分配一個Key),也能夠是ftok函數返回的一個關鍵字。
參數size指定段的大小。
參數flgs--八進制數,0666,轉化爲二進制後分別表明rw-rw-rw-
shmget成功返回段標識符,失敗返回-1(通常不會建立失敗,除非系統沒有內存).
注意:只有建立權限是0666的才能夠用命令行"ipcs -m"查看,其餘類型權限的共享內存區沒法被這個命令所查看。
//建立共享內存
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <sys/ipc.h>
#include <sys/shm.h>

int main(int arg, char *args[])
{
    int shmid=shmget(IPC_PRIVATE,sizeof(char)*1024,0666);
    if(shmid==-1)
    {
        printf("error\n");
        return -1;
    }
    printf("建立共享內存成功!內存段標識符是%d\n",shmid);
    return 0;
}
在命令行執行"ipcs -m "顯示已經成功的建立了一塊共享內存區。
nattch字段顯示已經附加到這個內存區的進程數。

 

附加共享內存區
void * shmat(int shmid,void * shmaddr,int shmflg);
int shmdt(const * void shmaddr);
參數shmid是要附加的共享內存區標識符(在命令行執行ipcs -m 顯示)。
老是把參數shmaddr設爲0,0表示系統會自動在被附加的進程內建立一個內存段,映射到共享內存區。固然也能夠指定一個被附加的進程內的一塊內存,可是須要用戶本身malloc分配內存,並將地址傳給shmaddr參數,比較麻煩,通常使用系統自動分配。
參數shmflg能夠爲SHM_RDONLY,這意味着附加段是隻讀的,參數爲0時,表示能夠讀寫。
shmat成功返回被附加了段的地址,失敗返回-1,並設置errno,雖然返回值是指針類型,可是返回的的確是-1。
函數shmdt是將附加在shmaddr的段從調用進程的地址空間分離出去,這個地址必須是shmat返回的(即從本身進程內釋放被附加的共享內存,強調不是釋放系統的那個共享內存)。
注意:進程裏附加共享內存區的大小必定是和系統共享內存同樣大,爲了方便映射(兩塊內存不同大如何同步數據?)。
//建立附加共享內存
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/shm.h>

int main(int arg, char *args[])
{
    if (arg < 3)
    {
        printf("請輸入2個參數!\n");
        return -1;
    }
    int flag = 0;
    int shmid = 0;
    shmid = atoi(args[1]);
    flag = atoi(args[2]);
    //建立本進程被附加的共享內存
    void * shmbuf = NULL;
    shmbuf = shmat(shmid, 0, 0);
    /*
     編譯警告:warning: cast from pointer to integer of different size
     這句警告意思是指針類型大小和Int類型大小不一樣,根據之前的知識,指針都是4個字節大小,
     其實指針的大小不是固定的4個字節。32位cpu的計算機上是4字節,64位cpu的計算機上是8個字節。
     這是由於32位計算機中的地址是32位的(能夠在32位系統下查看指針的值例如--0x003bf9a3)
     可是在64位計算機中地址是64位的(能夠在64位系統下查看指針的值例如--0xffffffffffffffff)
     十六進制數字的1位等於二進制的4位
     雖然指針的值在32位系統和64位系統中有區別,可是一個字節的大小在兩個系統中是相同的,
     舉例說Int類型數據,無論是在32位系統和64位系統中都在內存中佔據4個字節大小的內存空間
     */
    if ((int) shmbuf == -1)
    {
        printf("建立附加共享內存區失敗!error message:%s\n", strerror(errno));
        return -1;
    }
    sleep(10);
    if (flag == 1)
    {
        //將數據寫入本進程本身的附加共享內存區
        //這裏系統共享內存區的大小是1kb
        read(STDIN_FILENO, shmbuf, sizeof(char) * 1024);
    } else if (flag == 2)
    {
        printf("%s", shmbuf);
    }
    return 0;
}
shmdt函數
--功能:將共享內存段與當前進程脫離
--參數
    shmarr:由shmat所返回的指針
--返回值:成功返回0,失敗返回-1
--注意:將共享內存段與當前進程脫離不等於刪除共享內存

 

釋放共享內存區
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
參數shmid是共享內存區段標識符,
參數cmd通常有三個值IPC_STAT(獲取共享內存區的狀態,由第三個參數獲取狀態),IPC_SET(設置共享內存區),IPC_RMID(刪除共享內存區,此時第三個參數通常傳0);
shmctl成功返回0,失敗返回-1,而且設置errno的值
//建立共享內存區
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(int arg,char * args[])
{
    if(arg<2)
    {
        printf("請輸入一個參數!\n");
        return -1;
    }
    int shmid=atoi(args[1]);
    int flag=shmctl(shmid,IPC_RMID,0);
    if(flag<0)
    {
        printf("error message:%s\n",strerror(errno));
        return -1;
    }
    printf("返回值是%d\n",flag);
    return 0;
}
命令行釋放共享內存區
在命令行執行"ipcrm -m shmid" 或者 "ipcrm shm shmid"
相關文章
相關標籤/搜索