unix/linux下的共享記憶體、信号量、隊列資訊管理,在unix/linux下,經常有因為共享記憶體、信号量,隊列等共享資訊沒有幹淨地清楚而引起一些問題。
1、ipcs 和 ipcrm 指令執行個體
檢視共享資訊的記憶體的指令是ipcs [-m|-s|-q]。
預設會列出共享記憶體、信号量,隊列資訊,-m列出共享記憶體,-s列出共享信号量,-q列出共享隊列
清除指令是ipcrm [-m|-s|-q] id。
ipcrm可用來删除對應的共享記憶體段、信号量、消息隊列;ipcrm本身隻能實作單個資源的删除,利用以下指令可實作批量删除(zhangsj版權所有,呵呵):
1.ipcs -s|grep 使用者名|cut -d" " -f2|xargs -n1 ipcrm -s
2.ipcs -s|awk '/使用者名/{print $2}'|xargs -n1 ipcrm -s
3.ipcs -s|awk '/使用者名/{system("ipcrm -s "$2)}'
4.for i in echo `ipcs|grep 使用者名|cut -d" " -f2`; do ipcrm -s $i; done
-m 删除共享記憶體,-s删除共享信号量,-q删除共享隊列。
更多參考:http://bbs.chinaunix.net/thread-1620394-1-1.html
[oracle@trade_as02 ~]$ ipcs -a
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x30024289 32768 futures 777 528384 1
0xca2fd414 491521 oracle 640 1730150400 16
------ Semaphore Arrays --------
key semid owner perms nsems
0x00028009 0 futures 666 1
0x0002800c 32769 futures 666 1
0x30024003 262146 futures 777 3
0x3002428a 294915 futures 777 2
0x3002428b 327684 futures 777 2
0x3002428c 360453 futures 777 2
0x3002428d 393222 futures 777 2
0x3002428e 425991 futures 777 2
0x52dff7d0 3964936 oracle 640 151
0x52dff7d1 3997705 oracle 640 151
0x52dff7d2 4030474 oracle 640 151
0x52dff7d3 4063243 oracle 640 151
0x52dff7d4 4096012 oracle 640 151
------ Message Queues --------
key msqid owner perms used-bytes messages
共享記憶體段有時不能馬上删除,需使用這個記憶體段的所有程序向OS發送detach指令時才有釋放,此時可以考慮删除程序使用的信号量,幫助釋放共享記憶體段
2、關鍵知識
,常用的方式是通過shmXXX函數族來實作利用共享記憶體進行存儲的。 如Shmget,類似于 malloc函數
3、共享記憶體函數
由shmget、shmat、shmdt、shmctl四個函數組成。下面的表格列出了這四個函數的函數原型及其具體說明。
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,錯誤原因存于error中
附加說明
上述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(把共享記憶體區對象映射到調用程序的位址空間)
#include <sys/types.h>
連接配接共享記憶體辨別符為shmid的共享記憶體,連接配接成功後把共享記憶體區對象映射到調用程序的位址空間,随後可像本地空間一樣通路
void *shmat(int shmid, const void *shmaddr, int shmflg)
msqid
共享記憶體辨別符
shmaddr
指定共享記憶體出現在程序記憶體位址的什麼位置,直接指定為NULL讓核心自己決定一個合适的位址位置
SHM_RDONLY:為隻讀模式,其他為讀寫模式
成功:附加好的共享記憶體位址
fork後子程序繼承已連接配接的共享記憶體位址。exec後該子程序與已連接配接的共享記憶體位址自動脫離(detach)。程序結束後,已連接配接的共享記憶體位址會自動脫離(detach)
EACCES:無權限以指定方式連接配接共享記憶體
EINVAL:無效的參數shmid或shmaddr
shmat(斷開共享記憶體連接配接)
與shmat函數相反,是用來斷開與共享記憶體附加點的位址,禁止本程序通路此片共享記憶體
int shmdt(const void *shmaddr)
shmaddr:連接配接的共享記憶體的起始位址
成功:0
本函數調用并不删除所指定的共享記憶體區,而隻是将先前用shmat函數連接配接(attach)好的共享記憶體脫離(detach)目前的程序
EINVAL:無效的參數shmaddr
shmctl(共享記憶體管理)
完成對共享記憶體的控制
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
cmd
IPC_STAT:得到共享記憶體的狀态,把共享記憶體的shmid_ds結構複制到buf中
IPC_SET:改變共享記憶體的狀态,把buf所指的shmid_ds結構中的uid、gid、mode複制到共享記憶體的shmid_ds結構内
IPC_RMID:删除這片共享記憶體
buf
共享記憶體管理結構體。具體說明參見共享記憶體核心結構定義部分
EACCESS:參數cmd為IPC_STAT,确無權限讀取該共享記憶體
EFAULT:參數buf指向無效的記憶體位址
EIDRM:辨別符為msqid的共享記憶體已被删除
EINVAL:無效的參數cmd或shmid
EPERM:參數cmd為IPC_SET或IPC_RMID,卻無足夠的權限執行