目錄
一、共享內存概念
?二、共享內存的一些函數
2.1 shmget 創建共享內存
2.2 shmat 訪問共享內存?
2.3?shmdt 解除共享內存的映射
2.4?shnctl 刪除共享內存段
三、共享內存?
3.1 創建測試進程
3.2 使用循環測試
?編輯
3.3?共享內存寫入程序
3.4 帶有信號量的共享內存?
一、共享內存概念
共享內存是一種進程間通信的方式,允許多個進程訪問和操作同一塊內存區域。這樣的內存區域被所有共享它的進程所擁有,進程可以將數據寫入共享內存區域,也可以從中讀取數據。共享內存在提高進程通信效率和降低開銷方面具有優勢,但也需要進行同步和互斥操作以避免數據競爭和沖突。
共享內存通常適用于需要高效地在進程間傳遞大量數據的場景,比如多個進程需要共享大型數據結構、圖形圖像處理或多媒體應用等。在使用共享內存時,需要注意管理內存的權限、同步訪問和處理異常情況等問題,以確保數據的一致性和安全性。
?二、共享內存的一些函數
2.1 shmget 創建共享內存
它的函數原型如下:
int shmget(key_t key, size_t size, int shmflg);
參數含義:
1. key: 用于標識共享內存段的鍵值,不同的進程使用相同的 key 值可以獲取到同一個共享內存2. size: 創建共享內存時,指定要申請的共享內存空間大小3. shmflg:?用于指定創建共享內存段的訪問權限和其他標志,比如權限位和內存段的創建方式等。常見的標志包括IPC_CREAT
(如果不存在則創建共享內存段)和?IPC_EXCL
(如果存在則返回錯誤)。shmget() 成功則返回共享內存的 ID, 失敗返回-1
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/shm.h>int main()
{int shmid = shmget((key_t)2345,128,IPC_CREAT|0600);if(shmid == -1){exit(1);}}
2.2 shmat 訪問共享內存?
函數shmat()
用于將共享內存段附加到調用進程的地址空間,并返回一個指向共享內存段起始地址的指針。
它的函數原型如下:
void* shmat(int shmid, const void *shmaddr, int shmflg);
參數含義:
shmid
: 表示要附加的共享內存段的標識符,通常是由shmget()
函數返回的共享內存標識符。
shmaddr
: 指定共享內存段連接到調用進程地址空間的地址。一般設置為?NULL,由系統自動選擇映射的虛擬地址空間
shmflg
: 用以指定附加共享內存段的附加方式。常見的標志包括SHM_RDONLY
(只讀方式附加共享內存段)和?SHM_RND
(指示共享內存段將在系統限定的地址范圍內附加)。?一般給 0, 可以給 SHM_RDONLY 為只讀模式,其他的為讀寫返回值:
? ? ? ?函數的返回值是一個指針,指向共享內存段的起始地址。 ?shmat()成功則返回共享內存的首地址,失敗返回 NULL
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/shm.h>int main()
{int shmid = shmget((key_t)2345,128,IPC_CREAT|0600);if(shmid == -1){exit(1);}char* s=(char*)shmat(shmid,NULL,0);if(s==(char*)-1){exit(1);}strcpy(s,"hello");shmdt(s);}
2.3?shmdt 解除共享內存的映射
當進程不再需要訪問共享內存時,需要使用?shmdt
?函數將共享內存段從進程地址空間中解除映射。其函數原型如下:
int shmdt(const void *shmaddr);
參數含義:
shmaddr
: 表示要分離的共享內存段的起始地址。通常是由shmat()
函數返回的指針,指向共享內存段的起始位置。返回值:
????????當成功分離共享內存段時,函數返回0。如果出現錯誤,函數會返回-1,并且可以通過檢查
errno
變量來獲取錯誤信息。
2.4?shnctl 刪除共享內存段
函數shmctl()
用于控制共享內存段的屬性
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
參數含義:
shmid
: 共享內存段的標識符,通常由shmget()
函數返回。
cmd
: 控制命令,指定對共享內存段執行的操作類型。常見的命令有:
IPC_STAT
: 獲取共享內存段的狀態信息,并將其存儲在buf
指向的shmid_ds
結構體中。IPC_SET
: 設置共享內存段的權限模式,需要提供buf
指向的shmid_ds
結構體。IPC_RMID
: 從系統中刪除共享內存段,同時釋放其占用的資源。
buf
: 指向一個shmid_ds
結構體的指針,用于存儲或傳遞共享內存段的狀態信息或權限設置。返回值:
????????函數成功執行時返回0,否則返回-1,并通過設置
errno
變量來指示錯誤類型。
三、共享內存?
3.1 創建測試進程
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/shm.h>int main()
{int shmid = shmget((key_t)2345,128,IPC_CREAT|0600);if(shmid == -1){exit(1);}char* s=(char*)shmat(shmid,NULL,0);if(s==(char*)-1){exit(1);}printf("s=%s\n",s);// 打印共享內存的地址shmdt(s);}
運行結果:
3.2 使用循環測試
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/shm.h>int main()
{int shmid = shmget((key_t)2345,128,IPC_CREAT|0600);if(shmid == -1){exit(1);}char* s=(char*)shmat(shmid,NULL,0);if(s==(char*)-1){exit(1);}while(1){if(strncmp(s,"end",3) == 0){break;}printf("s=%s\n",s);sleep(1);}shmdt(s);}
3.3?共享內存寫入程序
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/shm.h>int main()
{int shmid = shmget((key_t)2345,128,IPC_CREAT|0600);if(shmid == -1){exit(1);}char* s=(char*)shmat(shmid,NULL,0);if(s==(char*)-1){exit(1);}while(1){printf("input\n");char buff[128]={0};fgets(buff,128,stdin);strcpy(s,buff);if( strncmp(buff,"end",3) == 0){break;}}shmdt(s);
}
3.4 帶有信號量的共享內存?
首先要創建兩個信號量,一個設為0,另一個設為1。
頭文件代碼sem.h
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/sem.h>enum INDEX{SEM1=0,SEM2};union semun
{int val;
};void sem_init();//創建并初始化信號量
void sem_p(int index);
void sem_v(int index);
void sem_destroy();
sem.c代碼
#include"sem.h"static int semid=-1;void sem_init()//創建并初始化信號量
{semid=semget((key_t)1234,2,IPC_CREAT|IPC_EXCL|0600);if(semid==-1){semid=semget((key_t)1234,2,0600);if(semid==-1){printf("semget err\n");}}else{int arr[2]={1,0};for(int i=0;i<2;i++){union semun a;a.val=arr[i];if(semctl(semid,i,SETVAL,a)==-1){printf("semctl init err\n");}}}
}void sem_p(int index)
{struct sembuf buf;buf.sem_num=index;buf.sem_op=-1;//pbuf.sem_flg=SEM_UNDO;if(semop(semid,&buf,1) == -1){printf("op p err\n");}
}void sem_v(int index)
{struct sembuf buf;buf.sem_num=index;buf.sem_op=1;//vbuf.sem_flg=SEM_UNDO;if(semop(semid,&buf,1) == -1){printf("op v err\n");}
}void sem_destroy()
{if(semctl(semid,0,IPC_RMID) == -1){printf("semctl del\n");}
}
使用信號量的main.c代碼
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/shm.h>
#include"sem.h"int main()
{int shmid = shmget((key_t)2345,128,IPC_CREAT|0600);if(shmid == -1){exit(1);}char* s=(char*)shmat(shmid,NULL,0);if(s==(char*)-1){exit(1);}sem_init();//創建 初始化while(1){printf("input\n");char buff[128]={0};fgets(buff,128,stdin);sem_p(SEM1);//p s1strcpy(s,buff);sem_v(SEM2);//v s2if( strncmp(buff,"end",3) == 0){break;}}shmdt(s);
}
測試代碼test.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/shm.h>
#include"sem.h"int main()
{int shmid = shmget((key_t)2345,128,IPC_CREAT|0600);if(shmid == -1){exit(1);}char* s=(char*)shmat(shmid,NULL,0);if(s==(char*)-1){exit(1);}sem_init();while(1){sem_p(SEM2);if(strncmp(s,"end",3) == 0){break;}printf("s=%s\n",s);sem_v(SEM1);}shmdt(s);sem_destroy();exit(0);
}
運行結果: