IPC之共享內存

man 7 shm_overview編程

shm_overview - Overview of POSIX shared memory.ide

一樣,SystemV實現的共享內存是舊的機制,但應用普遍;Posix標準提供了新的統一接口。函數

共享內存是由內核出於在多個進程間交換信息的目的而留出的一塊內存區(段)。若是段的權限設置恰當,每一個要訪問該段內存的進程均可以把它映射到本身私有的地址空間中。若是一個進程更新了段中數據,那麼其餘進程當即回看到更新。由一個進程建立的段也能夠由另外一個進程讀寫。共享內存這一名稱表達出是由多個進程分享對段及其保存的數據的訪問權這一含義。共享內存很像內存映射文件。spa

Posix API:code

shm_open, ftruncate, mmap, munmap, shm_unlink, close, fstat, fchown, fchmod.blog

System V API:接口

shmget,shmat,shmdt進程

#include <sys/types.h>ip

#include <sys/ipc.h>內存

#include <sys/shm.h>

int shmget(key_t key, int size, int flags);

flags能夠是一個或多個IPC_CREAT、IPC_EXCL和一組權限位(模式)按位「或」的結果。權限位以八進制表示。IPC_EXCL確保若是段已經存在,執行失敗,而不是返回一個已經存在的段的標示符。IPC_CREAT指出若是沒有和key關聯的段就應該建立一個新段。key既能夠是IPC_PRIVATE也能夠是ftok函數返回的一個關鍵字。參數size指定段的大小,但它以PAGE_SIZE的值爲界,這個值是某種處理器自己頁的大小(intel是4KB)。shmget成功返回段標識符,出錯返回-1。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>

#define BUFSZ  4096

int main(void)
{
    int shmid;

    if((shmid = shmget(IPC_PRIVATE, BUFSZ, 0666)) < 0)
    {   
        perror("shmget");
        exit(EXIT_FAILURE);
    }   

    printf("segment created: %d\n", shmid);

    system("ipcs -m\n");
    
    exit(EXIT_SUCCESS);
}
~$./a.out 
segment created: 65538

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 0          yuxi       666        4096       0                       
0x00000000 32769      yuxi       666        4096       0                       
0x00000000 65538      yuxi       666        4096       0 

shmget只是建立了共享內存區,進程要把它映射到本身的地址空間才能使用它,調用shmat完成。

#include <sys/types.h>

#include <sys/shm.h>

void *shmat(int shmid, const char *shmaddr, int shmflg);

int shmdt(const void *shmaddr);

在函數shmat中,若是shmaddr爲NULL,則內核會把段映射到調用進程的地址空間中它所選定的位置。假如shmaddr不爲NULL,而且shmflg指定SHM_RND,則attach發生在附近的最小倍數SHMLBA。不然shmaddr必須是頁對齊的地址。通常老是把shmaddr設置爲0。flags能夠爲SHM_RDONLY,這意味着被附加的段是隻讀的。不然,被附加的段默認是可讀寫的。若是shmat調用成功,則返回附加了段的地址。不然,它返回-1而且設置errno變量。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(int argc, char *argv[])
{
    int shmid;
    char *shmbuf;

    if(argc != 2)
    {   
        puts("USAGE: atshm <identifier>");
        exit(EXIT_FAILURE);
    }   
    shmid = atoi(argv[1]);

    if((shmbuf = shmat(shmid, 0, 0)) < (char *)0)
    {   
        perror("shmat");
        exit(EXIT_FAILURE);
    }   
    printf("segment attached at %p\n", shmbuf);

    system("ipcs -m");

    if((shmdt(shmbuf)) < 0)
    {
        perror("shmdt");
        exit(EXIT_FAILURE);
    }

    puts("segment detached");

    system("ipcs -m");

    exit(EXIT_SUCCESS);
}
~$./a.out 32769
segment attached at 0xb7709000

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 0          yuxi       666        4096       0                       
0x00000000 32769      yuxi       666        4096       1                       
0x00000000 65538      yuxi       666        4096       0                       

segment detached

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 0          yuxi       666        4096       0                       
0x00000000 32769      yuxi       666        4096       0                       
0x00000000 65538      yuxi       666        4096       0

 使用舉例:

include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <fcntl.h>
#include <ctype.h>

#define BUFSZ 4096

int main(int argc, char **argv)
{
    int shmid;
    char *shmbuf;
    int fd; 
    int i;

    if(argc != 2)
    {   
        puts("USAGE: opshm <identifier>");
        exit(EXIT_FAILURE);
    }   
    shmid = atoi(argv[1]);

    if((shmbuf = shmat(shmid, 0, 0)) < (char *)0)
    {
        perror("shmat");
        exit(EXIT_FAILURE);
    }

    if((shmbuf = malloc(sizeof(char) * BUFSZ)) < (char *)0)
    {
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    for(i = 0; i < BUFSZ; ++i)
    {
        shmbuf[i] = rand();
    }

    fd = open("opshm.out", O_CREAT | O_WRONLY, 0600);
    write(fd, shmbuf, BUFSZ);

    free(shmbuf);

    exit(EXIT_SUCCESS);
}

建立shm舉例

void *init_shm(void)
{
    key_t key;
    int shmid;
    void *addr = NULL;

    key = ftok(SHM_PATH, SHM_PROJ);
    if(key == -1) 
    {   
        perror("ftok()");
        return NULL;
    }       

    shmid = shmget(key, sizeof(struct shm_block), IPC_CREAT | 0600);
    if(shmid == -1)
    {
        perror("shmget: ");
        return NULL;
    }
    addr = shmat(shmid, 0, 0);
    if (addr == (void *)-1)
    {
        perror("shmat()");
        return NULL;
    }

    return addr;
}

經過命令ipcs -m能夠查看共享內存信息。

注:大部份內容來自《GNU/LINUX編程指南》

相關文章
相關標籤/搜索