複製鏈接
請複製以下鏈接發送給好友

shmget

鎖定
用於Linux進程通信(IPC)共享內存。共享內存函數由shmget、shmat、shmdtshmctl四個函數組成。
中文名
shmget
外文名
shared memory segment
簡    介
用於Linux進程通信共享內存
所需頭文件
#include
函數説明
並返回共享內存標識符

目錄

shmget簡介

shmget函數原型
shmget(得到一個共享內存標識符或創建一個共享內存對象)
所需頭文件
#include <sys/ipc.h>
#include <sys/shm.h>
函數説明
得到一個共享內存標識符或創建一個共享內存對象並返回共享內存標識符
函數原型
int shmget(key_t key, size_t size, int shmflg)
函數傳入值
key
0(IPC_PRIVATE):會建立新共享內存對象
大於0的32位整數:視參數shmflg來確定操作。通常要求此值來源於ftok返回的IPC鍵值
size
大於0的整數:新建的共享內存大小,以字節為單位
0:只獲取共享內存時指定為0
shmflg
0:取共享內存標識符,若不存在則函數會報錯
IPC_CREAT:當shmflg&IPC_CREAT為真時,如果內核中不存在鍵值與key相等的共享內存,則新建一個共享內存;如果存在這樣的共享內存,返回此共享內存的標識符
IPC_CREAT|IPC_EXCL:如果內核中不存在鍵值 與key相等的共享內存,則新建一個共享內存;如果存在這樣的共享內存則報錯
函數返回值
成功:返回共享內存的標識符
出錯:-1,錯誤原因存於errno中
附加説明
上述shmflg參數為模式標誌參數,使用時需要與IPC對象存取權限(如0600)進行|運算來確定信號量集的存取權限
錯誤代碼
EINVAL:參數size小於SHMMIN或大於SHMMAX
EEXIST:預建立key所指的共享內存,但已經存在
EIDRM:參數key所指的共享內存已經刪除
ENOSPC:超過了系統允許建立的共享內存的最大值(SHMALL)
ENOENT:參數key所指的共享內存不存在,而參數shmflg未設IPC_CREAT位
EACCES:沒有權限
ENOMEM:核心內存不足
在Linux環境中,對開始申請的共享內存空間進行了初始化,初始值為0x00。
如果用shmget創建了一個新的消息隊列對象時,則shmid_ds結構成員變量的值設置如下:
shm_lpid、shm_nattach、shm_atime、shm_dtime設置為0。
msg_ctime設置為當前時間。
shm_segsz設成創建共享內存的大小。
shmflg的讀寫權限放在shm_perm.mode中。
shm_perm結構的uid和cuid成員被設置成當前進程的有效用户ID,gid和cuid成員被設置成當前進程的有效組ID。
其他共享內存函數
shmat
shmat(把共享內存區對象映射到調用進程的地址空間)
所需頭文件
#include <sys/types.h>
#include <sys/shm.h>
函數説明
連接共享內存標識符為shmid的共享內存,連接成功後把共享內存區對象映射到調用進程的地址空間,隨後可像本地空間一樣訪問
函數原型
void *shmat(int shmid, const void *shmaddr, int shmflg)
函數傳入值
shmid
共享內存標識符
shmaddr
指定共享內存出現在進程內存地址的什麼位置,直接指定為NULL讓內核自己決定一個合適的地址位置
shmflg
SHM_RDONLY:為只讀模式,其他為讀寫模式
函數返回值
成功:附加好的共享內存地址
出錯:-1,錯誤原因存於errno中
附加説明
fork後子進程繼承已連接的共享內存地址。exec後該子進程與已連接的共享內存地址自動脱離(detach)。進程結束後,已連接的共享內存地址會自動脱離(detach)
錯誤代碼
EACCES:無權限以指定方式連接共享內存
EINVAL:無效的參數shmid或shmaddr
ENOMEM:核心內存不足
shmdt函數原型
shmdt(斷開共享內存連接)
所需頭文件
#include <sys/types.h>
#include <sys/shm.h>
函數説明
與shmat函數相反,是用來斷開與共享內存附加點的地址,禁止本進程訪問此片共享內存
函數原型
int shmdt(const void *shmaddr)
函數傳入值
shmaddr:連接的共享內存的起始地址
函數返回值
成功:0
出錯:-1,錯誤原因存於errno中
附加説明
本函數調用並不刪除所指定的共享內存區,而只是將先前用shmat函數連接(attach)好的共享內存脱離(detach)目前的進程
錯誤代碼
EINVAL:無效的參數shmaddr
shmctl(共享內存管理)
所需頭文件
#include <sys/types.h>
#include <sys/shm.h>
函數説明
完成對共享內存的控制
函數原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
函數傳入值
shmid
共享內存標識符
cmd
IPC_STAT:得到共享內存的狀態,把共享內存的shmid_ds結構複製到buf中
IPC_SET:改變共享內存的狀態,把buf所指的shmid_ds結構中的uid、gid、mode複製到共享內存的shmid_ds結構內
IPC_RMID:刪除這片共享內存
buf
共享內存管理結構體。具體説明參見共享內存內核結構定義部分
函數返回值
成功:0
出錯:-1,錯誤原因存於errno中
錯誤代碼
EACCES:參數cmd為IPC_STAT,卻無權限讀取該共享內存
EFAULT:參數buf指向無效的內存地址
EIDRM:標識符為shmid的共享內存已被刪除
EINVAL:無效的參數cmd或shmid
EPERM:參數cmd為IPC_SET或IPC_RMID,卻無足夠的權限執行

shmget應用範例

1、父子進程通信範例 父子進程通信範例,shm.c源代碼如下:
#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 pid ;
    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 ) ;
        if ( (long)shmaddr == -1 )
        {
            perror("shmat addr error") ;
            return -1 ;
        }
        strcpy( shmaddr, "Hi, I am child process!\n") ;
        shmdt( shmaddr ) ;
        return 0;
    } else if ( pid > 0) {
        sleep(3 ) ;
        int flag = shmctl( shmid, IPC_STAT, &buf) ;
        if ( flag == -1 )
        {
            perror("shmctl shm error") ;
            return -1 ;
        }
        printf("shm_segsz =%ld 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 ( (long)shmaddr == -1 )
        {
            perror("shmat addr error") ;
            return -1 ;
        }
        printf("%s", shmaddr) ;
        shmdt( shmaddr ) ;
        shmctl(shmid, IPC_RMID, NULL) ;
    }else{
        perror("fork error") ;
        shmctl(shmid, IPC_RMID, NULL) ;
    }
    return 0 ;
}

編譯 gcc shm.c –o shm。
執行 ./shm,執行結果如下:
shm_segsz =1024 bytes
shm_cpid = 9503
shm_lpid = 9504
Hi, I am child process!
2、多進程讀寫範例
多進程讀寫即一個進程寫共享內存,一個或多個進程讀共享內存。下面的例子實現的是一個進程寫共享內存,一個進程讀共享內存。
(1)下面程序實現了創建共享內存,並寫入消息。
shmwrite.c源代碼如下:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>

typedef struct{
    char name[8];
    int age;
} people;

int main(int argc, char** argv)
{
    int shm_id,i;
    key_t key;
    char temp[8];
    people *p_map;
    char pathname[30] ;
    strcpy(pathname,"/tmp") ;
    key = ftok(pathname,0x03);
    if(key==-1)
    {
        perror("ftok error");
        return -1;
    }
    printf("key=%d\n",key) ;
    shm_id=shmget(key,4096,IPC_CREAT|IPC_EXCL|0600);
    if(shm_id==-1)
    {
        perror("shmget error");
        return -1;
    }
    printf("shm_id=%d\n", shm_id) ;
    p_map=(people*)shmat(shm_id,NULL,0);
    memset(temp, 0x00, sizeof(temp)) ;
    strcpy(temp,"test") ;
    temp[4]='0';
    for(i = 0;i<3;i++)
    {
        temp[4]+=1;
        strncpy((p_map+i)->name,temp,5);
        (p_map+i)->age=0+i;
    }
    shmdt(p_map) ;
    return 0 ;
}

(2)下面程序實現從共享內存讀消息。
shmread.c源代碼如下:
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct{
    char name[8];
    int age;
} people;

int main(int argc, char** argv)
{
    int shm_id,i;
    key_t key;
    people *p_map;
    char pathname[30] ;
    strcpy(pathname,"/tmp") ;
    key = ftok(pathname,0x03);
    if(key == -1)
    {
        perror("ftok error");
        return -1;
    }
    printf("key=%d\n", key) ;
    shm_id = shmget(key,0, 0);
    if(shm_id == -1)
    {
        perror("shmget error");
        return -1;
    }
    printf("shm_id=%d\n", shm_id) ;
    p_map = (people*)shmat(shm_id,NULL,0);
    for(i = 0;i<3;i++)
    {
        printf( "name:%s\n",(*(p_map+i)).name );
        printf( "age %d\n",(*(p_map+i)).age );
    }
    shmctl(shm_id, IPC_RMID, NULL) ;
    if(shmdt(p_map) == -1)
    {
        perror("detach error");
        return -1;
    }
    return 0 ;
}

(3)編譯與執行
① 編譯gcc shmwrite.c -o shmwrite。
② 執行./shmwrite,執行結果如下:
key=50453281
shm_id=688137
③ 編譯gcc shmread.c -o shmread。
④ 執行./shmread,執行結果如下:
key=50453281
shm_id=688137
name:test1
age 0
name:test2
age 1
name:test3
age 2
再執行./shmwrite,執行結果如下:
key=50453281
shmget error: File exists
⑥ 使用ipcrm -m 688137刪除此共享內存。