IPC_EXCL 只有在共享內存不存在的時候,新的共享內存才創建,不然就產生錯誤
例子一:假設鍵值爲key,建立一個共享內存大小爲4k,訪問權限爲066,若是已經存在則返回其標識號
int shmid;
if( (shmid = shmget(key,4 * 1024,0666 | IPC_CREAT)) < 0)
{
perror("Fail to shmget");
exit(EXIT_FAILURE)
}
例子2、假設鍵值爲key,建立一個共享內存大小爲1k,訪問權限爲0666,若是已經存在則報錯
int shmid;
if((shmid = shmget(key,1024,0666 | IPC_CREAT | IPC_EXCL)) < 0)
{
perror("Fail to shmget");
exit(EXIT_FAILURE);
}
B.共享內存的映射
函數shmat將標識號爲shmid共享內存映射到調用進程的地址空間中。
參數說明:
shmid : 要映射的共享內存區標識符
shmaddr : 將共享內存映射到指定地址(若爲NULL,則表示由系統自動完成映射)
shmflg : SHM_RDONLY 共享內存只讀
默認0:共享內存可讀寫。
返回值 :調用成功放回映射後的地址 ,出錯放回(void *)-1;
C.取消共享內存與用戶進程之間的映射
參數shmaddr是shmat映射成功放回的地址。
注意:當一個進程再也不須要共享內存段時,它將調用shmdt()系統調用取消這個段,可是,這並非從內核真正地刪除這個段,
而是把相關shmid_ds結構的shm_nattch域的值減1,
當這個值爲0時,內核才從物理上刪除這個共享段。
D.控制共享內存
參數說明:
shmid 共享內存標識ID
cmd IPC_STAT獲得共享內存的狀態
IPC_SET改變共享內存的狀態
IPC_RMID刪除共享內存
buf 是一個結構體指針。IPC_STAT的時候,取得的狀態放在這個結構體中。若是要改變共享內存的狀態,用這個結構體指定;
注意:
1.IPC_RMID命令實際上不從內核刪除一個段,而是僅僅把這個段標記爲刪除,實際的刪除發生最後一個進程離開這個共享段時。
2.當cmd爲IPC_RMID時,第三個參數應爲NULL。呵呵,大部分咱們都是這樣作,用這個函數刪除共享內存。
案例探究:
- #include <sys/shm.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <semaphore.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #define BUFF_SIZE 1024
- int father_do_work(int shmid)
- {
- char *buf;
- void *shmaddr;
- sem_t *prsem;
- sem_t *pwsem;
- //有名信號量
- if((prsem = sem_open("rsem",O_CREAT,0666,0)) == SEM_FAILED)
- {
- perror("Fail to sem open");
- return -1;
- }
-
- //有名信號量
- if((pwsem = sem_open("wsem",O_CREAT,0666,1)) == SEM_FAILED)
- {
- perror("Fail to sem open");
- return -1;
- }
- //映射共享內存
- if((shmaddr = shmat(shmid,NULL,0)) == (void *)-1)
- {
- perror("Fail to shmat");
- exit(EXIT_FAILURE);
- }
- buf = (char *)shmaddr;
- while(1)
- {
- if(sem_wait(pwsem) < 0)
- {
- perror("Fail to sem wait");
- break;
- }
- printf(">");
- fgets(buf,BUFF_SIZE,stdin);
- buf[strlen(buf) - 1] = '\0';
-
- if(sem_post(prsem) < 0)
- {
- perror("Fail to sem post");
- break;
- }
-
- if(strncmp(buf,"quit",4) == 0)
- {
- if(shmdt(shmaddr) < 0)
- {
- perror("Fail to shmaddr");
- exit(EXIT_FAILURE);
- }
- break;
- }
-
- usleep(500);
- }
-
- return 0;
- }
- int child_do_work(int shmid)
- {
- char *buf;
- void *shmaddr;
- sem_t *prsem;
- sem_t *pwsem;
- //
- if((prsem = sem_open("rsem",O_CREAT,0666,0)) == SEM_FAILED)
- {
- perror("Fail to sem open");
- return -1;
- }
- if((pwsem = sem_open("wsem",O_CREAT,0666,1)) == SEM_FAILED)
- {
- perror("Fail to sem open");
- return -1;
- }
- //映射共享內存
- if((shmaddr = shmat(shmid,NULL,0)) == (void *)-1)
- {
- perror("Fail to shmat");
- exit(EXIT_FAILURE);
- }
- buf = (char *)shmaddr;
- while(1)
- {
- if(sem_wait(prsem) < 0)
- {
- perror("Fail to prsem");
- break;
- }
- printf("read buf : %s.\n",buf);
- if(sem_post(pwsem) < 0)
- {
- perror("Fail to pwsem");
- break;
- }
- if(strncmp(buf,"quit",4) == 0)
- {
- if(shmdt(shmaddr) < 0)
- {
- perror("Fail to shmaddr");
- exit(EXIT_FAILURE);
- }
- break;
- }
- }
-
- return 0;
- }
- int main()
- {
- int shmid;
- int pid;
- void *shmaddr;
-
- //建立共享內存
- if((shmid = shmget(IPC_PRIVATE,BUFF_SIZE,0666 | IPC_CREAT)) < 0)
- {
- perror("Fail to shmget");
- exit(EXIT_FAILURE);
- }
- if((pid = fork()) < 0)
- {
- perror("Fail to fork");
- exit(EXIT_FAILURE);
-
- }else if(pid == 0){
-
- child_do_work(shmid);
-
- }else{
-
- father_do_work(shmid);
- wait(NULL);
- if(shmctl(shmid,IPC_RMID,NULL) < 0)
- {
- perror("Fail to shmctl");
- exit(EXIT_FAILURE);
- }
- }
- exit(EXIT_SUCCESS);
- }
運行結果: