Linux systemV消息隊(duì)列和信號(hào)量詳解
一、消息隊(duì)列
1、實(shí)現(xiàn)原理
操作系統(tǒng)在內(nèi)核建立一個(gè)隊(duì)列,通信的兩個(gè)進(jìn)程AB以數(shù)據(jù)塊的形式將需要發(fā)送的數(shù)據(jù)pushback到隊(duì)列中,數(shù)據(jù)塊是一個(gè)結(jié)構(gòu)體,其中有字段標(biāo)識(shí)該數(shù)據(jù)塊是誰發(fā)送的,所以我們只要讓不同的進(jìn)程看到同一個(gè)隊(duì)列就可以了
2、系統(tǒng)調(diào)用接口
(一)創(chuàng)建獲取一個(gè)消息隊(duì)列
msgget函數(shù)的主要功能是創(chuàng)建一個(gè)新的消息隊(duì)列或者獲取一個(gè)已經(jīng)存在的消息隊(duì)列的標(biāo)識(shí)符
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflg);
返回值:成功返回一個(gè)msgid,失敗返回-1
key:ftok函數(shù)的返回值msgflg:標(biāo)識(shí)符
| 函數(shù) | msgflg | 作用 | 示例 |
|---|---|---|---|
| msgget | IPC_CREAT | 如果指定鍵對(duì)應(yīng)的消息隊(duì)列不存在,則創(chuàng)建一個(gè)新的消息隊(duì)列;若已存在,則直接返回該消息隊(duì)列的標(biāo)識(shí)符 | msgget(key, IPC_CREAT | 0666) |
| msgget | IPC_EXCL | 通常與 IPC_CREAT 一起使用,若同時(shí)設(shè)置這兩個(gè)標(biāo)志,當(dāng)消息隊(duì)列已經(jīng)存在時(shí),msgget 調(diào)用會(huì)失敗并返回 -1,errno 會(huì)被設(shè)置為 EEXIST | msgget(key, IPC_CREAT | IPC_EXCL | 0666) |
| msgget | 0600 | 消息隊(duì)列的所有者具有讀寫權(quán)限,所屬組和其他用戶沒有任何權(quán)限 | msgget(key, 0600) |
| msgget | 0660 | 消息隊(duì)列的所有者和所屬組具有讀寫權(quán)限,其他用戶沒有權(quán)限 | msgget(key, 0660) |
| msgget | 0666 | 消息隊(duì)列的所有者、所屬組和其他用戶都具有讀寫權(quán)限 | msgget(key, 0666) |
(二)控制消息隊(duì)列
msgctl用于控制消息隊(duì)列的系統(tǒng)調(diào)用函數(shù),通常用于對(duì)消息隊(duì)列執(zhí)行各種管理操作,如獲取消息隊(duì)列狀態(tài)、設(shè)置消息隊(duì)列屬性以及刪除消息隊(duì)列等
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgctl(int msgid, int cmd, struct msqid_ds *buf);
返回值:返回0表示操作成功,返回-1表示操作失敗
msgid:消息隊(duì)列標(biāo)識(shí)符,msgget函數(shù)返回值cmd:msgctl函數(shù)的cmd參數(shù)常用命令如下:
| 命令 | 說明 |
|---|---|
| IPC_STAT | 獲取消息隊(duì)列的狀態(tài)信息,將信息存儲(chǔ)在buf指向的msqid_ds結(jié)構(gòu)中。這些信息包括消息隊(duì)列的權(quán)限、所有者信息、消息隊(duì)列的大小、當(dāng)前消息數(shù)量等 |
| IPC_SET | 根據(jù)buf指向的msqid_ds結(jié)構(gòu)中的值,設(shè)置消息隊(duì)列的屬性??梢栽O(shè)置的屬性包括消息隊(duì)列的權(quán)限、隊(duì)列的最大字節(jié)數(shù)等 |
| IPC_RMID | 刪除指定的消息隊(duì)列。調(diào)用該命令后,消息隊(duì)列將被立即刪除,所有排隊(duì)的消息都會(huì)被丟棄,并且與該消息隊(duì)列相關(guān)的資源也會(huì)被釋放 |
| MSG_INFO | 獲取與消息隊(duì)列相關(guān)的系統(tǒng)資源使用信息,例如當(dāng)前系統(tǒng)中消息隊(duì)列的總數(shù)、系統(tǒng)允許的最大消息隊(duì)列數(shù)等 |
| MSG_STAT | 該命令與IPC_STAT類似,但它返回的是一個(gè)指向struct msg_info結(jié)構(gòu)的指針,該結(jié)構(gòu)包含了更多關(guān)于消息隊(duì)列的統(tǒng)計(jì)信息,如發(fā)送和接收消息的字節(jié)數(shù)等 |
buf:一個(gè)指向msgid_ds結(jié)構(gòu)體的指針,用于存儲(chǔ)或提供消息隊(duì)列的相關(guān)信息,msqid_ds結(jié)構(gòu)包含了消息隊(duì)列的各種屬性,如隊(duì)列的權(quán)限、所有者信息、消息隊(duì)列的大小等
(三)發(fā)送消息
msgsnd用于向消息隊(duì)列發(fā)送消息的系統(tǒng)調(diào)用函數(shù),它允許進(jìn)程將一個(gè)消息添加到指定的消息隊(duì)列中
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg);
返回值:成功返回0,失敗返回-1
msgid:消息隊(duì)列標(biāo)識(shí)符,msgget函數(shù)返回值msgp:指向要發(fā)送的消息結(jié)構(gòu)體的指針,該結(jié)構(gòu)體的第一個(gè)成員必須是 long 類型,用于指定消息的類型,后續(xù)可以包含消息的數(shù)據(jù)部分msgsz:消息數(shù)據(jù)部分的長(zhǎng)度,即msgp所指向結(jié)構(gòu)體中除第一個(gè)long類型成員之外的數(shù)據(jù)長(zhǎng)度msgflg:該位置為0就是不設(shè)置
| 函數(shù) | msgflg | 作用 | 示例 |
|---|---|---|---|
| msgsnd | IPC_NOWAIT | 非阻塞發(fā)送消息,當(dāng)消息隊(duì)列已滿,無法立即發(fā)送消息時(shí),如果設(shè)置了該標(biāo)志,msgsnd 函數(shù)會(huì)立即返回 -1,errno 被設(shè)置為 EAGAIN;若未設(shè)置該標(biāo)志,msgsnd 函數(shù)會(huì)阻塞,直到消息隊(duì)列有空間可以發(fā)送消息 | msgsnd(msgid, &msgbuf, sizeof(msgbuf.mtext), IPC_NOWAIT) |
(四)在消息隊(duì)列中獲取數(shù)據(jù)塊
msgrcv用于從消息隊(duì)列接收消息的系統(tǒng)調(diào)用函數(shù),它允許進(jìn)程從指定的消息隊(duì)列中獲取消息
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
返回值:成功返回實(shí)際收到的消息數(shù)據(jù)部分的字節(jié)數(shù),不包括最前面的long
前兩個(gè)參數(shù)與前面相同
msgsz:接收消息時(shí)用于存儲(chǔ)消息數(shù)據(jù)部分的緩沖區(qū)的最大長(zhǎng)度msgtyp:如果等于0,那該函數(shù)只接收消息隊(duì)列中的第一條消息,如果大于0,接收消息隊(duì)列中消息類型為msgtyp的第一條消息,如果小于0,接收消息隊(duì)列中消息類型小于等于msgtyp絕對(duì)值的最小類型的第一條消息msgflg:該位置為0就是不設(shè)置
| 函數(shù) | msgflg | 作用 | 示例 |
|---|---|---|---|
| msgrcv | IPC_NOWAIT | 當(dāng)消息隊(duì)列中沒有符合要求的消息時(shí),如果設(shè)置了該標(biāo)志,msgrcv 函數(shù)會(huì)立即返回 -1,errno 被設(shè)置為 ENOMSG;若未設(shè)置該標(biāo)志,msgrcv 函數(shù)會(huì)阻塞,直到有符合要求的消息進(jìn)入消息隊(duì)列 | msgrcv(msgid, &msgbuf, sizeof(msgbuf.mtext), msgtype, IPC_NOWAIT) |
| msgrcv | MSG_NOERROR | 如果接收到的消息長(zhǎng)度超過了指定的緩沖區(qū)大小,若設(shè)置了該標(biāo)志,消息會(huì)被截?cái)酁榫彌_區(qū)大小,多余部分會(huì)被丟棄,msgrcv 函數(shù)正常返回;若未設(shè)置該標(biāo)志,msgrcv 函數(shù)會(huì)返回 -1,errno 被設(shè)置為 E2BIG | msgrcv(msgid, &msgbuf, sizeof(msgbuf.mtext), msgtype, MSG_NOERROR) |
二、信號(hào)量
1、原理
信號(hào)量是一種用于實(shí)現(xiàn)進(jìn)程間同步與互斥的機(jī)制,信號(hào)量本質(zhì)上是一個(gè)整數(shù)變量,用于控制對(duì)共享資源的訪問,它可以看作是一種特殊的計(jì)數(shù)器,其值表示當(dāng)前可用的共享資源數(shù)量,信號(hào)量的值可以被多個(gè)進(jìn)程或線程讀取和修改,通過對(duì)信號(hào)量的操作,進(jìn)程或線程可以協(xié)調(diào)對(duì)共享資源的訪問
信號(hào)量的工作基于兩個(gè)基本操作:P操作(wait操作)和V操作(signal操作)
P操作:當(dāng)一個(gè)進(jìn)程或線程需要訪問共享資源時(shí),它會(huì)執(zhí)行 P 操作。P 操作會(huì)將信號(hào)量的值減 1,如果減 1 后信號(hào)量的值大于等于 0,表示當(dāng)前有可用的資源,進(jìn)程或線程可以繼續(xù)訪問;如果減 1 后信號(hào)量的值小于 0,表示沒有可用的資源,進(jìn)程或線程會(huì)被阻塞,直到有其他進(jìn)程或線程釋放資源V 操作:當(dāng)一個(gè)進(jìn)程或線程使用完共享資源后,它會(huì)執(zhí)行 V 操作,V 操作會(huì)將信號(hào)量的值加 1,如果加 1 后信號(hào)量的值小于等于 0,表示有其他進(jìn)程或線程正在等待該資源,此時(shí)會(huì)喚醒一個(gè)等待的進(jìn)程或線程
2、系統(tǒng)調(diào)用接口
(一)創(chuàng)建獲取一個(gè)信號(hào)量
semget是用于創(chuàng)建或獲取信號(hào)量集的系統(tǒng)調(diào)用函數(shù)
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget(key_t key, int nsems, int semflg);
返回值:成功返回信號(hào)量標(biāo)識(shí)符semid,失敗返回-1
nsems:表示要?jiǎng)?chuàng)建或獲取的信號(hào)量集中信號(hào)量的數(shù)量,如果是創(chuàng)建新的信號(hào)量集則必須大于 0,如果是獲取已有的信號(hào)量集則可以為0semflg:標(biāo)志位,用于指定創(chuàng)建或獲取信號(hào)量集的方式和權(quán)限
(二)控制信號(hào)量
semctl是用于控制信號(hào)量集的系統(tǒng)調(diào)用函數(shù),它可以對(duì)信號(hào)量集進(jìn)行多種操作,如初始化信號(hào)量的值、獲取信號(hào)量的狀態(tài)、刪除信號(hào)量集等
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semctl(int semid, int semnum, int cmd, ...);
返回值:取決于cmd的當(dāng)前值,對(duì)于 GETVAL 命令,返回指定信號(hào)量的當(dāng)前值,對(duì)于 IPC_STAT、IPC_SET 和 IPC_RMID 等命令,返回 0 表示成功
semid:信號(hào)量標(biāo)識(shí)符,semget函數(shù)返回semnum:信號(hào)量集中信號(hào)量的編號(hào),編號(hào)從 0 開始,如果 cmd 操作不需要針對(duì)特定的信號(hào)量(如刪除整個(gè)信號(hào)量集),則可以忽略該參數(shù),通常將其設(shè)為 0cmd:要執(zhí)行的命令,指定了對(duì)信號(hào)量集或特定信號(hào)量的操作類型
(三)PV操作
semop用于對(duì)信號(hào)量集執(zhí)行操作的系統(tǒng)調(diào)用函數(shù),它允許進(jìn)程對(duì)一個(gè)或多個(gè)信號(hào)量進(jìn)行原子性的 P和 V操作,從而實(shí)現(xiàn)進(jìn)程間的同步與互斥
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semop(int semid, struct sembuf *sops, unsigned nsops);
返回值:成功返回0,失敗返回-1
sops:指向struct sembuf結(jié)構(gòu)體數(shù)組的指針,該數(shù)組包含了要對(duì)信號(hào)量集執(zhí)行的操作序列nsops:sops數(shù)組中元素的數(shù)量,即要執(zhí)行的操作序列的長(zhǎng)度
三、systemV IPC方法的比較
1、描述IPC資源的結(jié)構(gòu)體
描述共享內(nèi)存IPC資源結(jié)構(gòu)體:
struct shmid_kernel /* private to the kernel */
{
struct kern_ipc_perm shm_perm;
struct file * shm_file;
int id;
unsigned long shm_nattch;
unsigned long shm_segsz;
time_t shm_atim;
time_t shm_dtim;
time_t shm_ctim;
pid_t shm_cprid;
pid_t shm_lprid;
struct user_struct *mlock_user;
};
描述消息隊(duì)列IPC資源結(jié)構(gòu)體:
struct msg_queue {
struct kern_ipc_perm q_perm;
time_t q_stime; /* last msgsnd time */
time_t q_rtime; /* last msgrcv time */
time_t q_ctime; /* last change time */
unsigned long q_cbytes; /* current number of bytes on queue */
unsigned long q_qnum; /* number of messages in queue */
unsigned long q_qbytes; /* max number of bytes on queue */
pid_t q_lspid; /* pid of last msgsnd */
pid_t q_lrpid; /* last receive pid */
struct list_head q_messages;
struct list_head q_receivers;
struct list_head q_senders;
};
描述信號(hào)量IPC資源結(jié)構(gòu)體:
struct sem_array {
struct kern_ipc_perm sem_perm; /* permissions .. see ipc.h */
time_t sem_otime; /* last semop time */
time_t sem_ctime; /* last change time */
struct sem *sem_base; /* ptr to first semaphore in array */
struct sem_queue *sem_pending; /* pending operations to be processed */
struct sem_queue **sem_pending_last; /* last pending operation */
struct sem_undo *undo; /* undo requests on this array */
unsigned long sem_nsems; /* no. of semaphores in array */
};
他們有一個(gè)同樣的特點(diǎn)就是第一個(gè)參數(shù)都是struct kern_ipc_perm類型的
struct kern_ipc_perm
{
spinlock_t lock;
int deleted;
key_t key;
uid_t uid;
gid_t gid;
uid_t cuid;
gid_t cgid;
mode_t mode;
unsigned long seq;
void *security;
};
2、操作系統(tǒng)對(duì)IPC資源進(jìn)行管理
所有的IPC資源都有一個(gè)struct kern_ipc_perm結(jié)構(gòu),所以操作系統(tǒng)通過數(shù)組將這些struct kern_ipc_perm結(jié)構(gòu)組織起來
ipc_ids是 Linux 內(nèi)核中用于管理IPC資源的核心數(shù)據(jù)結(jié)構(gòu)
struct ipc_ids {
int in_use;//記錄當(dāng)前系統(tǒng)中正在使用的IPC資源的數(shù)量
int max_id;//表示系統(tǒng)中允許的最大IPC標(biāo)識(shí)符值
unsigned short seq;//是一個(gè)序列號(hào),用于生成唯一的IPC標(biāo)識(shí)符
unsigned short seq_max;//是序列號(hào)的最大值
struct semaphore sem;//這是一個(gè)信號(hào)量,用于對(duì)IPC資源的并發(fā)訪問進(jìn)行同步控制
struct ipc_id_ary nullentry;//一個(gè)空的ipc_id_ary結(jié)構(gòu)
struct ipc_id_ary* entries;//指向ipc_id_ary結(jié)構(gòu)體的指針
};struct ipc_id_ary {
int size;
struct kern_ipc_perm *p[0];
};這里的柔性數(shù)組p的作用就是維護(hù)當(dāng)前操作系統(tǒng)中所有IPC資源,我們通過強(qiáng)制類型轉(zhuǎn)換來通過這個(gè)數(shù)組里存的struct ipc_id_ary*找到具體的IPC對(duì)象,因?yàn)?code>kern_ipc_perm是這三個(gè)結(jié)構(gòu)體中的第一個(gè)成員,我們只要知道了一個(gè)kern_ipc_perm的地址,就相當(dāng)于知道了某個(gè)具體IPC對(duì)象的起始地址,然后通過強(qiáng)制類型轉(zhuǎn)換就可以訪問到該IPC對(duì)象中的所有成員屬性,這樣就實(shí)現(xiàn)了對(duì)一個(gè)具體IPC對(duì)象的訪問,如((struct shmid_kernel*)p[0])->q_stime,在kern_ipc_perm中有字段來標(biāo)識(shí)該kern_ipc_perm是屬于哪種IPC資源,操作系統(tǒng)就知道要將其強(qiáng)制轉(zhuǎn)化成什么類型了,我們?cè)谟脩魧用嫔鲜褂玫模?code>shmid、msqid、semid在內(nèi)核上看就是p數(shù)組的下標(biāo)
ipc_id_arry屬于操作系統(tǒng),不屬于任何進(jìn)程,數(shù)組下標(biāo)是線性遞增的,但不會(huì)因?yàn)?code>IPC資源的釋放而改變它的遞增屬性,即當(dāng)前操作系統(tǒng)中最后一個(gè)IPC資源的下標(biāo)是100,釋放掉這個(gè)IPC資源,下一次再創(chuàng)建IPC資源的時(shí)候它的下標(biāo)是101,而不是100,當(dāng)遞增到一定值的時(shí)候,會(huì)回到0
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
CentOS 7 中firewall-cmd命令詳細(xì)介紹
這篇文章主要介紹了 CentOS 7 中firewall-cmd命令詳細(xì)介紹的相關(guān)資料,這里對(duì)CentOS 7的firewall-cmd命令一一介紹,希望能幫助開始使用的朋友,需要的朋友可以參考下2016-11-11
windows 10 + vwware+centos 6.5虛擬機(jī)系統(tǒng)安裝Tomcat
這篇文章主要介紹了windows 10 + vwware+centos 6.5虛擬機(jī)系統(tǒng)安裝Tomcat的相關(guān)資料,需要的朋友可以參考下2017-01-01
基于linux配置selenium環(huán)境并實(shí)現(xiàn)運(yùn)行
這篇文章主要介紹了基于linux配置selenium環(huán)境并實(shí)現(xiàn)運(yùn)行,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
Linux中使用Cron定時(shí)執(zhí)行SQL任務(wù)的實(shí)現(xiàn)步驟
在Linux系統(tǒng)中,計(jì)劃任務(wù)(Cron)是一種強(qiáng)大的工具,可以自動(dòng)執(zhí)行預(yù)定的任務(wù),它非常適合定期運(yùn)行腳本、備份數(shù)據(jù)、清理臨時(shí)文件等一系列重復(fù)性任務(wù),本文給大家介紹了如何在Linux中使用Cron定時(shí)執(zhí)行SQL任務(wù),需要的朋友可以參考下2024-11-11
Apache ab并發(fā)負(fù)載壓力測(cè)試實(shí)現(xiàn)方法
Apache的ab命令模擬多線程并發(fā)請(qǐng)求,測(cè)試服務(wù)器負(fù)載壓力,也可以測(cè)試nginx、lighthttp、IIS等其它Web服務(wù)器的壓力2019-09-09
Linux zabbix自定義監(jiān)控及報(bào)警實(shí)現(xiàn)過程解析
這篇文章主要介紹了linux zabbix自定義監(jiān)控及報(bào)警實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08

