linux IPC---共享內存

共享內存

共享內存是允許兩個或多個進程共享同一塊內存區域,因爲進程可以直接讀寫內存,不需要任何數據的拷貝,這是一種最快的進程間通信方式。共享內存是多進程之間的通信方法 ,這種方法通常用於一個程序的多進程間通信,實際上多個程序間也可以通過共享內存來傳遞信息。當然,多個進程同時訪問共享區就得需要一些同步機制,如信號量或互斥鎖等,這些以後再記錄,本文先講最簡單的共享內存使用方式。

linux共享內存操作的四個函數

shmget函數:創建一個共享內存對象並返回共享內存標識符。
shmat函數:把創建的共享內存映射到具體的進程空間去,映射後就可以在本進程使用這塊地址。
shmctl函數:共享內存管理,完成對共享內存的控制。
shmdt函數:撤銷映射共享內存,但是並不刪除所指定的共享內存區,而只是將先前用shmat函數連接好的共享內存脫離目前的進程。

shmget 函數

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key,int size,int shmflg)

返回值:若成功,返回共享內存段標識符;若出錯,返回-1
參數說明:

  • Key:IPC_PRIVATE (爲0,比較常見的一種)
  • Size:共享內存區大小
  • Shmflg:同 open 函數的權限位,也可以用八進制表示法

shmat函數

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
char *shmat(int shmid,const void *shmaddr,int shmflg)

返回值:若成功,返回被映射的段地址;若出錯,返回-1
參數說明:

  • shmid:要映射的共享內存區標識符
  • shmaddr:將共享內存映射到指定位置(若爲 0 則表示把該段共享內存映射到調用進程的地址空間)
  • Shmflg
    - SHM_RDONLY:共享內存只讀
    - 默認 0:共享內存可讀寫

shmctl函數

#include <sys/types.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf)

返回值:若成功,返回0;若出錯,返回-1
參數含義:

  • shmid:共享內存標識符
  • cmd:

    • IPC_STAT:得到共享內存的狀態,把共享內存的shmid_ds結構複製到buf中
    • IPC_SET:改變共享內存的狀態,把buf所指的shmid_ds結構中的uid、gid、mode複製到共享內存的shmid_ds結構內
    • IPC_RMID:刪除這片共享內存
  • buf:共享內存管理shmid_ds結構體。

以下是 shmid_ds 結構:

struct shmid_ds  
{  
    struct ipc_perm shm_perm;   /* operation permission struct */  
    size_t          shm_segsz;  /* size of segment in bytes */  
    pid_t           shm_lpid;   /* pid of last shmop() operation */  
    pid_t           shm_cpid;   /* pid of creator */  
    shmatt_t        shm_nattch; /* number of current attaches */  
    time_t          shm_atime;  /* last-attach time */  
    time_t          shm_dtime;  /* last-detach time */  
    time_t          shm_ctime;  /* last-change time */  
}; 

shmdt函數

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr)

返回值:若成功,返回0;若出錯,返回-1
參數說明:

  • Shmaddr:被映射的共享內存段地址

示例程序

/* share_memory.c*/

#include <unistd.h>  
#include <stdio.h>  
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#include <sys/shm.h>
#define BUFF 1024
int main ()   
{   
    int shmid;
    pid_t pid; 
    char *shmaddr;//共享內存地址
    /*創建共享內存*/
    if((shmid=shmget(IPC_PRIVATE,BUFF,0666))<0)
    {
        perror("shmget");
        exit(-1);
    }
    else
        printf("Create shared memory,id = %d\n",shmid);

    if ((pid = fork()) < 0)
    {
        perror("fork");
        exit(-1);
    }
    else if (pid == 0) //子進程
    {
        /*映射共享內存*/
        if((shmaddr=shmat(shmid,0,0))<(char *)0)
        {
            perror("shmat");
            exit(-1);
        }
        else
            printf("I am child,shmat shared memory success\n"); 
        //子進程往共享內存寫數據
        strcpy( shmaddr, "from child process\n");
        //snprintf(shmaddr, 13, "%012d", 12345);
        //本函數調用並不刪除所指定的共享內存區,而只是將先前用shmat函數連接(attach)好的共享內存脫離(detach)目前的進程
        shmdt(shmaddr);
        return 0;
    }
    else //父進程
    {
        //保證子進程已經往共享內存寫入數據了
        sleep(2);
        /*映射共享內存*/
        if((shmaddr=shmat(shmid,0,0))<(char *)0)
        {
            perror("shmat");
            exit(-1);
        }
        else
            printf("I am parent,shmat shared memory success\n");
        //讀取共享內存的數據
        printf("read from share memory: %s",shmaddr);
        shmdt(shmaddr);
        //等待子進程退出
        waitpid(pid,NULL,0);
        exit(0);
    }
    return 0;  
}

實驗結果:

ubuntu:~/test/process_test$ ./share_memory
Create shared memory,id = 0
I am child,shmat shared memory success
I am parent,shmat shared memory success
read from share memory: from child process

以上程序,我們調用shmget函數創建共享內存區,然後調用fork函數創建子進程,在子進程中調用shmat映射共享內存地址,然後往共享內存區寫數據。在父進程中,同樣調用shmat函數映射共享內存區,然後從共享內存區讀取子進程寫入的數據。

共享內存的簡單應用就說到這了,下次講消息隊列。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章