1.1 共享內存
1.1.1 數據結構
struct shmid_ds {
struct ipc_perm shm_perm; /* 超作許可權數據結構指針 */
int shm_segsz; /* 共享存儲段大小 (bytes) */
time_t shm_atime; /* 最後調用shmat時間 */
time_t shm_dtime; /* 最後調用shmdt的時間 */
time_t shm_ctime; /* 最後調用shmctl的改變的時間 */
unsigned short shm_cpid; /*創建者的進程ID */
unsigned short shm_lpid; /* 最後對共享存儲段進行操作的進程ID */
short shm_nattch; /* 當前連接數 */
};
struct ipc_perm {
key_t key;
ushort uid; /* owner euid and egid */
ushort gid;
ushort cuid; /* creator euid and egid */
ushort cgid;
ushort mode; /* lower 9 bits of shmflg */
ushort seq; /* sequence number */
};
1.1.2 API
4.4 #include <sys/ipc.h> #include <sys/shm.h> |
打開創建存儲段 |
int shmget(key_t key, size_t size, int shmflg); |
返回:失敗-1, 成功返回非負的共享存儲段id |
第一個參數key是共享存儲關鍵字。它有特殊值IPC_PRIVATE表示總是創建一個進程私有的共享存儲段。
當key值不等於IPC_PRIVATE時,shmget動作取決於最後一個參數shmflg標誌:
1. IPC_CREAT 單獨設置此標誌,當系統中不存在相同key時,創建一個新的共享存儲段,否則返回已存在的共享存儲段。
2. IPC_EXCL 單獨設置不起作用。與 IPC_CREAT同時設置時,當系統中存在相同key時,錯誤返回。保證不會打開一個已存在的共享存儲段。
如果沒有指定IPC_CREATE並且系統中不存在相同key值的共享存儲段,將失敗返回。
第三個參數也可以設置共享存儲段的訪問權限,用或於上面的值操作。
第二個參數size指明要求的共享存儲段的大小。當key指定的共享存儲段已存在時,取值範圍爲0和已存在共享段大小。或簡單指定爲0。
成功後此函數返回共享存儲段id,同時創建於參數key相連的數據結構shmid_ds。此節構爲系統內部使用。
4.4 #include <sys/ipc.h> #include <sys/shm.h> |
存儲段控制函數。可獲得shmid_ds全部內容 |
int shmctl(int shmid, int cmd, struct shmid_ds *buf); |
返回:失敗-1並置errno, 成功返回0 |
第一個參數,必須由shmget返回的存儲段的id。cmd爲指定要求的操作。
CMD |
說明 |
參數 |
IPC_STAT |
放置與shmid相連的shmid_ds結構當前值於buf所指定用戶區 |
buf |
IPC_SET |
用buf指定的結構值代替與shmid相連的shmid_ds結構值 |
buf |
IPC_RMID |
刪除制定的信號量集合 |
|
SHM_LOCK |
鎖住共享存儲段。只能由超級管理員使用 |
|
SHM_UNLOCK |
unlock共享存儲段。只能由超級管理員使用 |
|
//創建/打開共享存儲段,連接他到用戶地址空間,返回他在用戶空間的地址
void* shminit(key_t key, char* mode_str, int target=1) {
int shmid;
int mode;
void* retval;
if (mode_str == NULL) {
mode = 0660;
} else {
sscanf(mode_str, "%o", &mode);
}
if (target == 0 ) {
if ((shmid = shmget(key, sizeof(exchange_T), mode | IPC_CREAT)) == -1)
perror("cannot create shm--");
} else if (target == 1) {
if ((shmid = shmget(key, sizeof(exchange_T), mode)) == -1)
perror("cannot get shm--");
}
if ((retval = shmat(shmid, (void *)0, 0)) == (void*)-1)
perror("shmmat");
return retval;
}
int rm_shm(key_t key) {
int status, shmid;
if ((shmid = shmget(key, sizeof(exchange_T), 0x660 | IPC_CREAT)) < 0)
perror("cannot get shm");
if ((status = shmctl(shmid, IPC_RMID, NULL)) < 0)
perror("shmctl IPC_RMID");
return status;
}
4.5 #include <sys/types.h> #include <sys/shm.h> |
存儲段連接 |
void *shmat(int shmid, const void *shmaddr, int shmflg); |
返回:失敗-1並置errno, 成功返回連接的實際地址 |
第一個參數,必須由shmget返回的存儲段的id
第二個參數指明共享存儲段要連接到的地址。0,系統爲我們創建一個適當的地址值。否則自己指定
第三個參數shmflg可以設成:SHM_RND, SHM_RDONLY。SHM_RND爲自己指定連接地址時用。SHM_RDONLY說明此存儲段只讀。
4.6 #include <sys/types.h> #include <sys/shm.h> |
存儲段分離 |
int shmdt(const void * shmaddr); |
返回:失敗-1並置errno, 成功返回0 |
分離由shmaddr指定的存儲段。此值應該由shmat返回的值。
此函數不是刪除共享存儲段,而是從當前進程分離存儲段。
當進程推出時,系統會自動分離它連接的所有共享段。
1.1.3 Example
client.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <errno.h>
#define SHMSZ 27
int main(void) {
exchange_T* shm;
int producer, consumer, i;
key_t key1 = 123, key2 = 456;
consumer = open_semaphore_set(key1, 1);
procuder = open_semaphore_set(key2, 1);
shm = (exchange_T*)shminit(ftock("shared", 0));
for (i = 0; ; i++) {
semaphore_V(consumer);
semaphore_P(producer);
printf("Data recieived:%s, sequence:%d/n", shm->buf, shm->seg);
if (strncmp(shm->buf, "end", 3) == 0)
break;
}
rm_semaphore(producer);
rm_semaphore(consumer);
exit(0);
}
server.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <errno.h>
#include "outshm.h"
#define SHMSZ 27
int main(void) {
exchage_T *shm, *s;
int producer, consumer, i;
char readbuf[BUFSIZE];
key_t key1 = 123, key2 = 456;
consumer = open_semaphore_set(key1, 1);
init_a_semaphore(consumer, 0, 0);
producer = open_semaphore_set(key2, 1);
init_a_semaphore(producer, 0, 0);
shm = (exchange_T*)shminit(ftok("shared", 0));
for(i = 0; ; i++) {
printf("Enter some text:");
fgets(readbuf, BUFSIZE, stdin);
semaphore_P(consumer);
shm->seq = i;
sprintf(shm->buf, "%s", readbuf);
semaphore_V(producer);
if(strncmp(readbuf, "end", 3) == 0)
break;
}
exit(0);
}