跟訊息佇列一樣,共用記憶體也有自己的資料結構,如下:
struct shmid_ds {
struct ipc_perm shm_perm; /* Ownership and permissions */
size_t
shm_segsz; /* Size of segment (bytes) */
time_t
shm_atime; /* Last attach time */
time_t
shm_dtime; /* Last detach time */
time_t
shm_ctime; /* Last change time */
pid_t shm_cpid; /* PID of creator */
pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */
shmatt_t
shm_nattch; /* No. of current attaches */
...
};
同樣地,第一個成員是共有的IPC核心資料結構,其餘是私人成員。
以下是幾個共用記憶體函數:
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:用來建立共用記憶體
原型 int shmget(key_t key, size_t size, int shmflg);
參數
key:這個共用記憶體段名字
size:共用記憶體大小
shmflg:由九個許可權標誌構成,它們的用法和建立檔案時使用的mode模式標誌是一樣的
傳回值:成功返回一個非負整數,即該共用記憶體段的標識碼;失敗返回-1
功能:將共用記憶體段串連到進程地址空間
原型
void *shmat(int shmid, const void *shmaddr, int shmflg);
參數
shmid: 共用記憶體標識
shmaddr:指定串連的地址
shmflg:它的兩個可能取值是SHM_RND和SHM_RDONLY
傳回值:成功返回一個指標,指向共用記憶體第一個位元組;失敗返回-1
shmaddr為NULL,核心自動選擇一個地址
shmaddr不為NULL且shmflg無SHM_RND標記,則以shmaddr為串連地址。
shmaddr不為NULL且shmflg設定了SHM_RND標記,則串連的地址會自動向下調整為SHMLBA的整數倍。
公式:shmaddr - (shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示串連操作用來唯讀共用記憶體
功能:將共用記憶體段與當前進程脫離
原型 int shmdt(const void *shmaddr);
參數
shmaddr: 由shmat所返回的指標
傳回值:成功返回0;失敗返回-1
注意:將共用記憶體段與當前進程脫離不等於刪除共用記憶體段
功能:用於控制共用記憶體
原型 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
參數
shmid:由shmget返回的共用記憶體標識碼
cmd:將要採取的動作(有三個可取值)
buf:指向一個儲存著共用記憶體的模式狀態和存取權限的資料結構
傳回值:成功返回0;失敗返回-1
cmd 的取值如下,與訊息佇列類似:
IPC_STAT 把shmid_ds結構中的資料設定為共用記憶體的當前關聯值
IPC_SET 在進程有足夠許可權的前提下,把共用記憶體的當前關聯值設定為shmid_ds資料結構中給出的值
IPC_RMID 刪除共用記憶體段
下面寫兩個函數測試一下:
shm_write.c
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
|
#include<string.h> #include<stdio.h> #include<stdlib.h> #include<sys/ipc.h> #include<sys/msg.h> #include<sys/types.h> #include<unistd.h> #include<errno.h> #include<fcntl.h> #include<sys/stat.h> #include<sys/mman.h> #include<sys/ipc.h> #include<sys/shm.h>#define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) typedef struct stu { char name[32]; int age; } STU; int main(int argc, char *argv[]) { int shmid; shmid = shmget(1234, sizeof(STU), IPC_CREAT | 0666); if (shmid == -1) ERR_EXIT("shmget"); STU *p; p = shmat(shmid, NULL, 0); if (p == (void *) - 1) ERR_EXIT("shmat"); strcpy(p->name, "lisi"); p->age = 20; shmdt(p); return 0; } |
在上面程式中,先建立一塊共用記憶體,再映射到進程的地址空間。
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./shm_write
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x000004d2 0 simba 666 36 0
可以看到建立了一塊共用記憶體,位元組數為寫入的STU大小,natth 表示進程串連個數,若在上面程式的shmdt 之前sleep(n); 此時在另一視窗觀察,可發現串連數為1,進程退出時,串連數再次為0。
shm_read.c
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
|
#include<string.h> #include<stdio.h> #include<stdlib.h> #include<sys/ipc.h> #include<sys/msg.h> #include<sys/types.h> #include<unistd.h> #include<errno.h> #include<fcntl.h> #include<sys/stat.h> #include<sys/mman.h> #include<sys/ipc.h> #include<sys/shm.h>#define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) typedef struct stu { char name[32]; int age; } STU; int main(int argc, char *argv[]) { int shmid; shmid = shmget(1234, 0, 0); if (shmid == -1) ERR_EXIT("shmget"); STU *p; p = shmat(shmid, NULL, 0); if (p == (void *) - 1) ERR_EXIT("shmat"); printf("name = %s age = %d\n", p->name, p->age); shmdt(p); shmctl(shmid, IPC_RMID, NULL); return 0; } |
上面程式中,先開啟共用記憶體,若未知共用記憶體大小,size 可設為0,然後也映射到自身的進程地址空間,讀取資料,最後使用shmctl 刪除這段共用記憶體。
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./shm_read
name = lisi age = 20
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
共用記憶體段已經被刪除。
參考:《UNP》