消息隊(duì)列
消息隊(duì)列是在內(nèi)核中實(shí)現(xiàn)的偶垮,并且是具有一定的優(yōu)先級(jí)的一種進(jìn)程間通信模型
POSIX PIC消息隊(duì)列
在unpv22e遗增,ch 5.1--5.5可以查看這些知識(shí)叫惊,POSIX消息隊(duì)列使用的頭函數(shù)是mqueue.h;使用的庫(kù)文件為librt.so做修;消息隊(duì)列通過(guò)結(jié)構(gòu)體:struct mq_arrt 來(lái)定義消息隊(duì)列屬性霍狰,結(jié)構(gòu)體中選項(xiàng)包含的有:mq_flags:標(biāo)志抡草,在mq_open時(shí)被初始化,mq_setattr可以進(jìn)行設(shè)置蔗坯;這個(gè)值通常為0或者O_NONBLOCK康震;mq_maxmsg:表示的是隊(duì)列中消息的最大個(gè)數(shù),只能在mq_open時(shí)被初始化宾濒;mq_msgsize:表示隊(duì)列中每個(gè)消息的最大值腿短;mq_curmsgs:表示當(dāng)前隊(duì)列消息長(zhǎng)度,在mq_getattr 時(shí)進(jìn)行獲榷κ蕖答姥;
關(guān)于消息隊(duì)列的八種操作:
?創(chuàng)建消息隊(duì)列:mqd_t mq_open(const char *name, int oflag,mode_t mode,struct mq_attr *attr);name:表示posix IPC名字谚咬;oflag:表示標(biāo)志鹦付,O_CREAT:表示在沒(méi)有時(shí),創(chuàng)建該對(duì)象择卦;O_EXCL:表示如果O_CREAT指定敲长,但是name不存在,就返回錯(cuò)誤信息秉继;O_NONBLOCK:表示以非阻塞方式打開(kāi)消息隊(duì)列祈噪;O_RDONLY:表示只讀;O_RDWR:表示讀寫尚辑;O_WRONLY:表示只寫辑鲤;mode:權(quán)限:S_IWUSR:表示用戶屬主寫權(quán)限;S_IRUSR:表示用戶屬主讀權(quán)限杠茬;S_IWGRP:表示組成員寫權(quán)限月褥;S_IRGRP:表示組成員讀權(quán)限;S_IWOTH:其他用戶寫權(quán)限瓢喉;S_IROTH:表示其他用戶讀權(quán)限宁赤;attr:表示隊(duì)列屬性:attr.mq_falg = 0;表示阻塞;attr.mq_flag = NONBLOCK栓票,表示非阻塞决左;返回值:-1,表示出錯(cuò)走贪;返回值為其他表示消息隊(duì)列描述符佛猛;
mqcreate.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <mqueue.h>
#include <fcntl.h>
#include <sys/stat.h>
#define FILE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) //0644
int main(int argc,char* argv[]){
int c,flag=0;
long maxmsg = 10;
long msglen = 8192;
while((c=getopt(argc,argv,"q:l:"))!=-1){
switch(c){
case 'q':
maxmsg = atoi(optarg);
break;
case 'l':
msglen = atoi(optarg);
break;
}
}
if(optind != argc-1){
printf("usage:%s [-q <maxmsg>] [-l <msglen>] <mqname>\n",argv[0]);
return 1;
}
struct mq_attr attr;
attr.mq_maxmsg = maxmsg;
attr.mq_msgsize = msglen;
mqd_t mqd = mq_open(argv[optind],O_CREAT,FILE_MODE,&attr);
if(-1 == mqd){
perror("mq_open error");
return 1;
}
}
刪除消息隊(duì)列:int mq_unlink(const char *name);name:表示posixIPC名字坠狡;返回值-1表示失敗挚躯,0表示成功;
mq_unlink.c
#include <stdio.h>
#include <stdlib.h>
#include <mqueue.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(){
mq_unlink("/tmp.test");
}
打開(kāi)消息隊(duì)列:mqd_t mq_open(const char *name,int oflag)擦秽;name:posix IPC表示名字码荔;oflag:表示標(biāo)志位漩勤,O_RDONLY,只讀缩搅;O_RDWR:表示讀寫越败;O_WRONLY:表示只寫;返回值為-1時(shí)表示出錯(cuò)硼瓣,返回值為其他表示描述符究飞;
隊(duì)列的打開(kāi)函數(shù)一般和發(fā)送或者接收一起出現(xiàn),就寫在一個(gè)函數(shù)里面堂鲤;
?關(guān)閉消息隊(duì)列:int mq_close(mqd_t mqdes);其中mqdes表示消息隊(duì)列描述符亿傅;返回值-1表示出錯(cuò),0表示成功瘟栖;
?設(shè)置消息隊(duì)列屬性:int mq_setattr(mqd_t mqdes,struct mq_attr *newattr,struct mq_attr *oldattr)葵擎;mqdes:表示消息隊(duì)列描述符;newattr:用于設(shè)置新屬性半哟,但是只能用于設(shè)置mq_falgs酬滤,其中0表示阻塞,NONBLOCK表示非阻塞寓涨;
oldattr:表示用于設(shè)置舊屬性盯串;函數(shù)返回值-1表示出錯(cuò),返回值0表示成功戒良;
mqsetattr.c:
#include <stdio.h>
#include <stdlib.h>
#include <mqueue.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(){
mqd_t mqd = mq_open("/tmp.test",O_RDWR);
if(-1 == mqd){
perror("mq_open error");
return;
}
struct mq_attr new_attr;
bzero(&new_attr,sizeof(new_attr));
new_attr.mq_flags = O_NONBLOCK;
struct mq_attr attr;
if(-1 == mq_setattr(mqd,&new_attr,&attr)){
perror("mq_setattr error");
return 1;
}
printf("flag:%ld,Max msg:%ld,Max msgsize:%ld,Cur msgnun:%ld\n",attr.mq_flags,attr.mq_maxmsg,attr.mq_msgsize,attr.mq_curmsgs);
}
獲取消息隊(duì)列屬性:int mq_getattr(mqd_t mqdes, struct mqdes,struct mq_attr *attr)体捏;mqdes:表示消息隊(duì)列描述符;attr:表示屬性信息糯崎;返回值:-1表示出錯(cuò)信息译打;0表示成功;
mqgetattr.c
#include <stdio.h>
#include <stdlib.h>
#include <mqueue.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(int argc,char* argv[]){
mqd_t mqd = mq_open(argv[1],O_RDONLY);
if(-1 == mqd){
perror("mq_open error");
return;
}
struct mq_attr attr;
mq_getattr(mqd,&attr);
printf("flag:%ld,Max msg:%ld,Max msgsize:%ld,Cur msgnun:%ld\n",attr.mq_flags,attr.mq_maxmsg,attr.mq_msgsize,attr.mq_curmsgs);
}
發(fā)送消息:int mq_send(mqd_t mqdes,const char *msg_ptr,size_t msg_len,unsigned msg_prio)拇颅;msg_ptr:表示消息隊(duì)列的指針;msg_len:表示消息長(zhǎng)度乔询,但是不能大于屬性值mq_msgsize的值樟插;msg_prio:表示優(yōu)先級(jí),消息在隊(duì)列中將按照優(yōu)先級(jí)大小順序來(lái)排列消息竿刁;如果消息隊(duì)列已滿黄锤,mq_send()函數(shù)將阻塞,知道油客埇的空間再次允許放置消息食拜;如果O_NONBLOCK被指定鸵熟,mq_send()那么將不會(huì)被阻塞,而是返回EAGAIN的值负甸;
mqsnd.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <mqueue.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#define FILE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) //0644
int main(int argc,char* argv[]){
int c,flags=O_WRONLY;
while((c=getopt(argc,argv,"n"))!=-1){
switch(c){
case 'n':
flags|=O_NONBLOCK;
break;
}
}
if(optind != argc-1){
printf("usage:%s [-n] <mqname> <message> <prio>\n");
return 1;
}
mqd_t mqd = mq_open(argv[optind],flags);
if(-1 == mqd){
perror("mq_open error");
return 1;
}
if(-1 == mq_send(mqd,argv[optind+1],strlen(argv[optind+1])+1,atoi(argv[optind+2]))){
perror("mq_send error");
return 1;
}
}
接收消息:ssize_t mq_recceive(mqd_t mqdes流强,char *msg_ptr痹届,size_t msg_len,unsigned *msg_len打月,unsigned *msg_prio);msg_prt:表示消息隊(duì)列的指針队腐;msg_len:表示消息長(zhǎng)度,不能夠大于屬性值mq_msgsize的值奏篙;msg_prio:表示優(yōu)先級(jí)柴淘,消息在隊(duì)列中將按照優(yōu)先級(jí)大小順序來(lái)排列消息;返回值:-1表示出錯(cuò)秘通,正數(shù)表示接收到消息的長(zhǎng)度为严;如果隊(duì)列為空,mq_receive()函數(shù)將阻塞肺稀,知道消息隊(duì)列中有新的消息第股。如果O_NONBLOCK被指定,mq_receive()將不會(huì)阻塞盹靴,而是返回EAGAIN錯(cuò)誤炸茧;
mqrecv.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <mqueue.h>
#include <fcntl.h>
#include <sys/stat.h>
#define FILE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) //0644
int main(int argc,char* argv[]){
int c,flags=O_RDONLY;
while((c=getopt(argc,argv,"n"))!=-1){
switch(c){
case 'n':
flags|=O_NONBLOCK;
break;
}
}
if(optind != argc-1){
printf("usage:%s [-n] <mqname>\n");
return 1;
}
mqd_t mqd = mq_open(argv[optind],flags);
if(-1 == mqd){
perror("mq_open error");
return 1;
}
char buf[BUFSIZ];
int prio;
if(-1 == mq_receive(mqd,buf,BUFSIZ,&prio)){
perror("mq_send error");
return 1;
}
printf("msg:%s\nprio:%d\n",buf,prio);
}
對(duì)于共享內(nèi)存的查看:man mq_overview,ls /dev/mqueue稿静;cat /dev/mqueue/PIC名字梭冠;
POSIX共享內(nèi)存
需要包含的頭文件sys/mman.h 需要包含的庫(kù)文件是librt.so
創(chuàng)建共享內(nèi)存:int shm_open(const char *name,int oflag,mode_t mode);name:表示posix IPC的名字;ofloag:表示標(biāo)志改备,O_CREAT:表示沒(méi)有的話控漠,創(chuàng)建該對(duì)象;
O_EXCL:如果O_CREAT指定悬钳,但是name不存在盐捷,就返回錯(cuò)誤;O_RDONLY:表示只讀默勾;O_RDWR:表示讀寫碉渡;O_TRUNC:表示如果存在就截?cái)啵籱ode:表示權(quán)限:S_IWUSR:表示用戶/屬主寫權(quán)限母剥;S_IRUSR:表示用戶/屬主讀權(quán)限滞诺;S_IR、WGRP:表示組成員寫權(quán)限环疼;S_IRGRP:表示組成員讀權(quán)限习霹;S_IWOTH:表示其他用戶寫權(quán)限;S_IROTH:表示其他用戶讀權(quán)限炫隶;函數(shù)的返回值-1表示出錯(cuò)淋叶;返回值為其他表示共享內(nèi)存描述符;
shmcreate.c
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
int fd = shm_open(argv[1],O_CREAT|O_RDWR,0644);
ftruncate(fd,atoi(argv[2]));
void* buf = NULL;
if(( buf = mmap(NULL,BUFSIZ,PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){
perror("mmap error\n");
return 1;
}
}
刪除int shm_unlink(const char *name)伪阶;name:表示posix IPC名字煞檩;返回值:-1表示出錯(cuò)处嫌,0表示成功;
shmunlink.c
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
shm_unlink(argv[1]);
}
修改文件的大行谓俊:int fruncate(int fd, off_t lenght)锰霜,fd:表示文件描述符;length:表示文件大小桐早,如果原來(lái)的文件帶下比參數(shù)length大癣缅,超過(guò)的部分就會(huì)被刪除;返回值:0表示成功哄酝;-1:失斢汛妗;這個(gè)函數(shù)用戶設(shè)置共享內(nèi)存的大小陶衅,fruncate(fd,len);
fruncate.c:
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
int fd = shm_open(argv[1],O_CREAT|O_RDWR,0644);
ftruncate(fd,atoi(argv[2]));
void* buf = NULL;
if(( buf = mmap(NULL,BUFSIZ,PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){
perror("mmap error\n");
return 1;
}
}
獲取文件信息:int fstat(int fd,struct stat *buf)屡立,fd:表示文件描述符;buf:是一個(gè)結(jié)構(gòu)體搀军,里面的參數(shù)分別表示:st_mode:表示文件對(duì)應(yīng)的模式膨俐,文件,目錄等罩句;st_size:表示普通文件焚刺,對(duì)應(yīng)的文件字節(jié)數(shù);st_atime:文件最后被訪問(wèn)的時(shí)間门烂;st_mtime:文件最后被修改訪問(wèn)的時(shí)間乳愉;st_ctime:文件狀態(tài)改變的時(shí)間;st_uid:文件所有者屯远;st_gid:文件所有者對(duì)應(yīng)的組蔓姚;st_blksize:文件內(nèi)容對(duì)應(yīng)的塊大小慨丐;st_blksize:文件內(nèi)容對(duì)應(yīng)的塊大衅缕辍;st_blocks:內(nèi)容對(duì)應(yīng)的塊數(shù)量房揭;st_ino:inode節(jié)點(diǎn)號(hào)备闲;st_dev:設(shè)備號(hào)碼;st_rdev:特殊設(shè)備號(hào)碼崩溪;st_nlink:文件的連接數(shù);
?st_mode:S_IFREG:表示一般文件斩松;S_IFDIR:表示目錄伶唯;S_IFSOCK:表示socket文件;S_IFIFO:表示先進(jìn)先出惧盹;S_IFLINK:表示符號(hào)鏈接乳幸;S_IFCHR:表示字符設(shè)置瞪讼;可以使用這些宏定義來(lái)判斷文件的類型;S_ISLINK(st_mode)粹断,S_ISREG(st_mode):判斷是否為一般文件符欠;S_ISDIR(st_mode):判斷是否為目錄;S_ISCHR(st_mode):判斷是否為字符文件瓶埋;S_ISBLK(st_mode):判斷是否為先進(jìn)先出文件希柿;S_ISSOCK(st_mode):判斷是否為socket;S_IFMT:文件類型的位遮罩养筒;S_IFBLK:區(qū)塊裝置曾撤;S_IUID:文件的(set user-id on execution)位;S_ISGID:文件的(set group-id on execution)晕粪;S_ISVTX:文件的sticky位挤悉;
?st_size:表示文件的大小巫湘;st_uid:表示屬主ID装悲;st_uid:屬主ID;st_guid:表示組ID尚氛;
?返回值:0表示成功诀诊;-1表示失敗怠褐;
暫時(shí)沒(méi)有代碼文件畏梆;
?建立內(nèi)存映射:void * mmap(void * start,size_t length, int prot,int flags, int fd, off_t offset):start:映射區(qū)的開(kāi)始地址,參數(shù)如果設(shè)置成NULL奈懒,表示有系統(tǒng)設(shè)置映射區(qū)的起始地址奠涌,如果考慮系統(tǒng)的可移植性,必須設(shè)置成為NULL磷杏;lenght:表示映射區(qū)的長(zhǎng)度溜畅,單位是字節(jié),但不足一頁(yè)按照一頁(yè)內(nèi)存進(jìn)行處理极祸;prot:內(nèi)存保護(hù)裝置 慈格;PROT_EXEC:表示頁(yè)內(nèi)容可以被執(zhí)行;PROT_READ:表示頁(yè)內(nèi)容可以被讀纫=稹浴捆;PROT_WAITE:表示頁(yè)面內(nèi)容可以被寫入;PROT_NONE:表示頁(yè)面內(nèi)容不可以被訪問(wèn)稿械;但是不能夠與文件的打開(kāi)模式?jīng)_突选泻;flags:映射對(duì)象的類型,MAP_SHARED:表示變動(dòng)共享;MAP_PRIVATE:表示變動(dòng)私有页眯;MAP_ANON:匿名內(nèi)存映射梯捕;fd:文件描述符,不能使套接字和中斷的fd窝撵,-1表示匿名內(nèi)存映射傀顾;
off_toset:表示被映射對(duì)象內(nèi)容的起點(diǎn);返回值:MAP_FAILED:表示失斅捣睢短曾;非MAP_FAILED:表示共享內(nèi)存地址;
mmapcreate.c
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
int fd = open("./mmap.txt",O_CREAT|O_RDWR,0644);
char str[] = "hello mmap\n";
lseek(fd,sizeof(str),SEEK_SET);
char* end = "\0";
write(fd,end,1);
void* buf = NULL;
if(( buf = mmap(NULL,sizeof(str),PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){
perror("mmap error\n");
return 1;
}
strcpy(buf,str);
munmap(buf,sizeof(str));
close(fd);
}
mmapcreate02.c
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
int fd = open("./mmap.txt",O_RDWR);
void* buf = NULL;
if(( buf = mmap(NULL,BUFSIZ,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){
perror("mmap error\n");
return 1;
}
printf("%s\n",buf);
strcpy(buf,"this sdfdsfdsfdsfdsfdsfdsfdsfdsfdsf\n");
munmap(buf,BUFSIZ);
close(fd);
}
mmapcreate03.c
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
int fd = open("./mmap.txt",O_CREAT|O_RDWR,0644);
char str[] = "hello mmap\n";
lseek(fd,sizeof(str),SEEK_SET);
char* end = "\0";
write(fd,end,1);
void* buf = NULL;
if(( buf = mmap(NULL,sizeof(str),PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){
perror("mmap error\n");
return 1;
}
strcpy(buf,str);
pause();
// munmap(str,sizeof(str));
// close(fd);
//_exit(0);
}
mmapcreate04.c
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
int fd = open("./mmap.txt",O_CREAT|O_RDWR,0644);
void* buf = NULL;
if(( buf = mmap(NULL,BUFSIZ,PROT_WRITE|PROT_READ,MAP_SHARED,fd,0)) == MAP_FAILED){
perror("mmap error\n");
return 1;
}
if(fork()){
strcpy(buf,argv[1]);
}else{
printf("%s\n",buf);
}
munmap(buf,BUFSIZ);
close(fd);
}
刪除內(nèi)存映射int munmap(void *start,size_t length)道批;start:映射內(nèi)存起始地址错英;length:表示內(nèi)存大小隆豹;返回值:0表示成功椭岩,-1表示失敗璃赡;需要注意的是關(guān)閉mmap中的文件描述符不能刪除內(nèi)存映射判哥;
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
int fd = open("./mmap.txt",O_CREAT|O_RDWR,0644);
char str[] = "hello mmap\n";
lseek(fd,sizeof(str),SEEK_SET);
char* end = "\0";
write(fd,end,1);
void* buf = NULL;
if(( buf = mmap(NULL,sizeof(str),PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){
perror("mmap error\n");
return 1;
}
strcpy(buf,str);
munmap(buf,sizeof(str));//表示的含義就是刪除內(nèi)存映射
close(fd);
}
同步操作:int msync(void * addr,size_t len,int flags);addr:表示映射內(nèi)存起始地址碉考;len:表示內(nèi)存大兴啤;flags:表示同步參數(shù)侯谁,MX_ASYNC锌仅,調(diào)用會(huì)立即返回,不等到跟新的完成墙贱,MS_SYNC:表示同步热芹,調(diào)用會(huì)等到更新完成之后返回;MS_INVALIDATE:通知使用該共享區(qū)域的進(jìn)程惨撇,數(shù)據(jù)已經(jīng)改變伊脓;在共享內(nèi)容更改之后,是的文件的其他映射失效魁衙;返回值:0:表示成功报腔;-1表示失敗剖淀;和文件的fflush相似纯蛾;
?查看:man shm_overview;ls /dev/shm纵隔;注意的是msg_open默認(rèn)生成共享內(nèi)存的大小是0翻诉,需要ftuncate設(shè)置大蟹俊;
POSIX信號(hào)量
資料可以查看unv22e米丘,頭文件是semaphore.h需要鏈接的庫(kù)文件是pthread;信號(hào)量類似于停車場(chǎng)的電子牌糊啡,信號(hào)量可以分為二值信號(hào)量拄查,0和1;計(jì)數(shù)信號(hào)量0和n棚蓄;信號(hào)量適用于控制多進(jìn)程訪問(wèn)共享資源的堕扶;
?信號(hào):P信號(hào):0表示掛起進(jìn)程;>0時(shí)梭依,減1稍算;V信號(hào):0表示恢復(fù)進(jìn)程;>0:表示加1役拴;信號(hào)的本質(zhì)是在任一時(shí)刻只能有一個(gè)進(jìn)程訪問(wèn)臨界區(qū)糊探;
命名信號(hào)量/基于文件
創(chuàng)建:sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);name:信號(hào)量IPC 名字河闰;oflag:O_CREAT:如果沒(méi)有這些對(duì)象就創(chuàng)建這個(gè)對(duì)象科平;O_EXCL:如果O_CREAT指定,但是name不存在姜性,就返回錯(cuò)誤瞪慧;mode:表示權(quán)限位;value:信號(hào)量初始值部念;返回值:非SEM_FAILED:信號(hào)量的指針弃酌;SEM_FAILED:出錯(cuò);
semopen.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <semaphore.h>
int main(int argc,char * argv[]){
sem_t* sem = sem_open(argv[1],O_CREAT|O_RDWR,0644,0);
fork();
int i=0;
for(;i<5;i++){
sleep(1);
sem_wait(sem);
printf("PID:%d,enter\n",getpid());
printf("PID:%d,do something\n",getpid());
printf("PID:%d,leave\n",getpid());
sem_post(sem);
}
}
打開(kāi):sem_t *sem_open(const char *name,int oflag)儡炼;sem_t *sem_open(const char *name,int oflag):name:信號(hào)量IPC名字妓湘;oflag:0;返回值:非SEM_FAILED:信號(hào)量的指針射赛;SEM_FAILED:出錯(cuò)多柑;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <semaphore.h>
int main(int argc,char * argv[]){
sem_t* sem = sem_open(argv[1],O_CREAT|O_RDWR,0644,0);
fork();
int i=0;
for(;i<5;i++){
sleep(1);
sem_wait(sem);
printf("PID:%d,enter\n",getpid());
printf("PID:%d,do something\n",getpid());
printf("PID:%d,leave\n",getpid());
sem_post(sem);
}
}
關(guān)閉:int sem_close(sem_t *sem);sem:信號(hào)量的指針楣责;返回值:-1表示出錯(cuò)竣灌,0表示成功;
刪除int sem_unlink(const char *name)秆麸;name:表示信號(hào)量IPC的名字初嘹;返回值-1出錯(cuò),0表示成功沮趣;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
無(wú)名信號(hào)量/基于內(nèi)存
初始化:int sem_init(sem_t *sem,int pshared,unsigned int value)屯烦;sem:表示信號(hào)量的指針;pshared:表示共享方式,0表示線程間共享驻龟,1表示進(jìn)程間共享温眉,但是需要共享內(nèi)存;value:信號(hào)量初始值翁狐;返回值:-1类溢,出錯(cuò),-表示成功露懒;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
銷毀:int sem_destory(sem_t *sem)闯冷,sem:表示信號(hào)量的指針;返回值位1表示出錯(cuò)懈词,0表示成功又官;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
掛出:int sem_post(sem_t *sem)赃蛛;sem:信號(hào)量的指針;返回值:-1表示出錯(cuò),0表示成功撼班;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
等待:int sem_wait(sem_t *sem)永淌;sem:表示信號(hào)量的指針粪般;返回值:-1表示出錯(cuò)察纯,0表示成功;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
嘗試等待:int sem_trywait(sem_t *sem)褐桌;sem:信號(hào)量的指針衰抑;返回值:-1表示出錯(cuò),0表示成功荧嵌;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
獲取信號(hào)量的值:int sem_getvalue(sem_t *sem,int *sval)呛踊;sem:信號(hào)量的指針;sval:信號(hào)量的值啦撮;返回值:0表示成功谭网,-1表示出錯(cuò);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
查看man sem_overview
?標(biāo)識(shí)/名字赃春,路徑名 /tmp.123
幾種方式的對(duì)比:
創(chuàng)建:文件:mqd_t mq_open(const char *name,int oflag,mode_t mode)愉择;消息隊(duì)列:mqd_t mqopen(const char *name,int oflag,mode_t mode,struct mq_arrt, *attr)共享內(nèi)存:int shm_open(const char *name,int oflag,mode_t);信號(hào)量:sem_t *sem_open(const char *name,int oflag,mode_t mode,unsigned int value);
刪除:文件:int unlink(const char *name)织中;消息隊(duì)列:mqd_t mq_unlink(const char *name)锥涕;共享內(nèi)存:int shm_unlink(const char *name) 信號(hào)量:sem_t *sem_unlink(const char *name);
System V PIC
system V消息隊(duì)列
需要包含的頭文件是sys/msg.h狭吼,需要自定義的結(jié)構(gòu)體msgbuf层坠,其中包含兩個(gè)選項(xiàng):消息類型:必須是long,必須是結(jié)構(gòu)體的第一個(gè)變量刁笙,mtext:標(biāo)識(shí)消息數(shù)據(jù)破花,可以隨意定義谦趣;
相關(guān)函數(shù)
消息獲取:int msgget(key_t key, int msgflg)座每;key:IPC鍵前鹅,key_t ftok(char *path,int id),path峭梳,id嫡纠;IPC_PRIVATE:通常用于親緣進(jìn)程;msgflg:IPC_CREAT:標(biāo)識(shí)創(chuàng)建延赌;IPC_CREAT | IPC_EXCL;權(quán)限:建議使用八進(jìn)制數(shù)字來(lái)進(jìn)行描述叉橱;返回值非負(fù)整數(shù)標(biāo)識(shí)消息隊(duì)列標(biāo)識(shí)挫以,-1:標(biāo)識(shí)失敗窃祝;
msghget.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/msg.h>
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
int main(){
int id = msgget(IPC_PRIVATE,O_CREAT|O_RDWR|0644);
if(-1 == id){
perror("msgget error");
return 1;
}
char str[] = "this is msg";
struct msgbuf* buf = malloc(sizeof(str)+sizeof(long));
buf->mtype= 10;
strcpy(buf->mtext,str);
if(fork()){
msgsnd(id,buf,sizeof(str),0);
}else{
sleep(1);
bzero(buf,sizeof(str)+sizeof(long));
msgrcv(id,buf,sizeof(str),-11,0);
printf("recv :%s",buf->mtext);
}
//msgctl(id,IPC_RMID,NULL);
}
消息發(fā)送:int msgsnd(int msgid,const void *msgptr,size_t msgsz,int msgflg)掐松;msgid:表示消息隊(duì)列標(biāo)識(shí);msgptr:表示消息結(jié)構(gòu)體粪小,是以一個(gè)長(zhǎng)整型成員變量開(kāi)始的結(jié)構(gòu)體大磺,
struct test_messsge{
long mtype; //must > 0
char mtext;// data;
};
msgsz:表示消息隊(duì)列長(zhǎng)度,但是不包括長(zhǎng)整型變量探膊;msgflg:用于控制函數(shù)的行為杠愧,0表示忽略;IPC_NOWAIT:表示如果消息隊(duì)列為空逞壁,就返回一個(gè)ENOMSG流济,并將控制權(quán)教會(huì)個(gè)調(diào)用函數(shù)的進(jìn)程。MSG_NOERROR:如果函數(shù)取得的消息長(zhǎng)度大于msgsz腌闯,將只返回msgsz的長(zhǎng)度绳瘟,剩下的部分就被丟棄了。MSG_EXCEPT:當(dāng)msgtyp > 0時(shí)姿骏,接受的類型不扥估m(xù)sgtype的第一條消息糖声;返回值:表示成功,-1表示失敺质荨蘸泻;
msgsnd.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/msg.h>
#include <fcntl.h>
struct msgbuf{
long mtype;
char mtext[1];
};
int main(int argc,char* argv[]){
int c,flag = 0;
while((c = getopt(argc,argv,"n")) !=-1){
switch(c){
case 'n':
flag=IPC_NOWAIT;
break;
}
}
if(optind != argc - 3){
printf("usage:%s [-n] <pathname> <message> <type>\n",argv[0]);
return 1;
}
int id = msgget(ftok(argv[optind],1),O_WRONLY);
if(-1 == id){
perror("msgget error");
return 1;
}
size_t msglen = strlen(argv[optind+1])+1;
struct msgbuf* buf = malloc(sizeof(long)+msglen);
buf->mtype = atoi(argv[optind+2]);
strcpy(buf->mtext,argv[optind+1]);
if(-1 == msgsnd(id,buf,msglen,flag)){
perror("fcntl error");
return 1;
}
}
接收消息:int msgrcv(int msgid,void *msgptr,size_t msgsz嘲玫,long msgtype蟋恬,int msgflg);msid:表示消息隊(duì)列標(biāo)識(shí)趁冈;msgptr:消息結(jié)構(gòu)體歼争,以一個(gè)長(zhǎng)整型成員變量開(kāi)始的結(jié)構(gòu)體拜马;
struct test_message{
long int message_type; // the data you which to transfer;
};
msgtype:標(biāo)識(shí)消息的接收類型沐绒,0標(biāo)識(shí)消息隊(duì)列中的第一個(gè)消息俩莽,大于0標(biāo)識(shí)獲取具有相同消息類型的第一個(gè)消息;小于0標(biāo)識(shí)獲取類型等于或者小于msgtype的絕對(duì)值的最小一個(gè)消息乔遮;msgflg:用于控制函數(shù)的行為扮超,0標(biāo)識(shí)忽略,IPC_NOWAIT:如果消息隊(duì)列為空則返回一個(gè)ENOMSG蹋肮,并將控制權(quán)返回給調(diào)用函數(shù)的進(jìn)程出刷;MSG_NOERROR,如果函數(shù)取得的消息隊(duì)列長(zhǎng)度大于msgsz坯辩,將只返回msgsz長(zhǎng)度的信息馁龟,剩下的部分機(jī)會(huì)被丟棄;MSG_EXCEPT:當(dāng)msgtype > 0 時(shí)漆魔,接受的類型不等于msgtype的第一個(gè)條消息坷檩;返回值:0標(biāo)識(shí)接收到的消息長(zhǎng)度,-1失敻穆铡矢炼;
msgrecv.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/msg.h>
#include <fcntl.h>
struct msgbuf{
long mtype;
char mtext[1];
};
int main(int argc,char* argv[]){
int c,flag = 0;
while((c = getopt(argc,argv,"n")) !=-1){
switch(c){
case 'n':
flag=IPC_NOWAIT;
break;
}
}
if(optind != argc - 2){
printf("usage:%s [-n] <pathname> <type>\n",argv[0]);
return 1;
}
int id = msgget(ftok(argv[optind],1),O_RDONLY);
if(-1 == id){
perror("msgget error");
return 1;
}
size_t msglen = BUFSIZ;
struct msgbuf* buf = malloc(sizeof(long)+msglen);
if(-1 == msgrcv(id,buf,msglen,atoi(argv[optind+1]),flag)){
perror("fcntl error");
return 1;
}
printf("read:%s",buf->mtext);
}
消息控制:int msgctl(int msgqid,int cmd,struct msgqid_ds *buf);msgqid:消息隊(duì)列標(biāo)識(shí)符阿纤;IPC_STAT:獲取當(dāng)前消息隊(duì)列控制信息句灌;IPC_SET:設(shè)置當(dāng)前消息隊(duì)列控制信息;IPC_RMID:刪除消息隊(duì)列欠拾;buf:消息隊(duì)列的模式結(jié)構(gòu)涯塔,msg_perm.mode:表示消息隊(duì)列讀寫模式;msg_qbytes:隊(duì)列最大大星迨础匕荸;msg_cbytes:當(dāng)前隊(duì)列的大小枷邪;msg_qnum:表示當(dāng)前隊(duì)列的消息數(shù)榛搔;返回值:0表示成功,-1表示失敹А践惑;
msgctl.c:標(biāo)識(shí)用于刪除消息
#include <stdio.h>
#include <sys/msg.h>
int main(int argc,char* argv[]){
int i;
for(i=1;i<argc;i++){
msgctl(atoi(argv[i]),IPC_RMID,NULL);
}
}
對(duì)于消息隊(duì)列的查看可以使用ipcs來(lái)進(jìn)行查看;
System V 共享內(nèi)存
資料查看unpv22e嘶卧,ch14尔觉,頭文件sys/shm.h
相關(guān)的函數(shù)
共享內(nèi)存的獲取:int shmget(key_t key, size_t size, int shmflg)芥吟;key:命名共享內(nèi)存IPC_PRIVATE侦铜,key_t ftok(const char *fname,int fd)专甩;fname:標(biāo)識(shí)已經(jīng)存在的文件路徑,id:表示子序號(hào)1--255钉稍;size:表示內(nèi)存容量涤躲,非0表示新建的共享內(nèi)存大小,0表示獲取共享內(nèi)存指定為0贡未;shmflg:IPC_CREAT:用于創(chuàng)建共享內(nèi)存种樱;IPC_CREAT | IPC_EXCL;權(quán)限:建議使用八進(jìn)制數(shù)字來(lái)表示俊卤;返回值:非負(fù)整數(shù)嫩挤,表示共享內(nèi)存表示符,-1表示失斚小岂昭;
shmget.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
int main(int argc,char* argv[]){
key_t key = ftok(argv[1],1);
if(-1 == key){
perror("ftok err");
return 1;
}
int shmid = shmget(key,atoi(argv[2]),IPC_CREAT|0644);
if(-1 == shmid){
perror("shmget err");
return 1;
}
printf("shmid:%d\n",shmid);
return 0;
}
共享內(nèi)存鏈接:void *shmat(int shmid,const void *shmaddr,int shmflg);shmid:共享內(nèi)存標(biāo)識(shí)符哺哼;shmaddr:指定共享內(nèi)存連接到當(dāng)前及才能拿中的地址位置;通常設(shè)置為NULL叼风,表示讓系統(tǒng)來(lái)選擇共享內(nèi)存的地址取董,這點(diǎn)是出于兼容性考慮;shmflg:表示標(biāo)志位无宿,SHM_RDONLY茵汰,只讀,0表示讀寫孽鸡;返回值:非負(fù)整數(shù)表示共享內(nèi)存指針蹂午,-1表示失敗彬碱;
shmread.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
int main(int argc,char* argv[]){
key_t key = ftok(argv[1],1);
if(-1 == key){
perror("ftok err");
return 1;
}
int shmid = shmget(key,0,O_RDONLY);
if(-1 == shmid){
perror("shmget err");
return 1;
}
void* buf = shmat(shmid,NULL,SHM_RDONLY);
printf("%s\n",buf);
shmdt(NULL);
printf("shmid:%d\n",shmid);
return 0;
}
共享內(nèi)存分離:int shmdt(const void *shmaddr)豆胸;shmaddr:表示共享內(nèi)存指針;返回值0表示成功巷疼,-1表示失斖砗;
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
共享內(nèi)存控制:int shmctl(int shmid,int cmd,struct shmid_ds *buf)嚼沿;shmid:共享內(nèi)存標(biāo)識(shí)符估盘;cmd:IPC_STAT,獲取當(dāng)前共享內(nèi)存控制信息骡尽;IPC_SET:設(shè)置當(dāng)前共享內(nèi)存控制信息遣妥;IPC_RMID:刪除共享內(nèi)存;buf:共享內(nèi)存信息結(jié)構(gòu):int shm_segsz攀细,表示共享內(nèi)存大小箫踩,shm_perm.mode:表示讀寫權(quán)限爱态;返回值:0表示成功,-1表示失敯嗵住肢藐;獲取共享內(nèi)存大小,shmctl(shmid,IPC_STAT,&buf)吱韭;buf.shm_segsz吆豹;刪除共享內(nèi)存:shmctl(shmid,IPC_RMID理盆,NULL)痘煤;
shmctl.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
int main(int argc,char* argv[]){
if(-1 == shmctl(atoi(argv[1]),IPC_RMID,NULL)){
perror("shmctl err");
return 1;
}
}
共享內(nèi)存也可以使用ipcs進(jìn)行查看;
System V信號(hào)量
&38195;unpv22e猿规,ch11衷快;頭文件是:、sys/sem.h
相關(guān)函數(shù)
信號(hào)量的獲纫塘:int semget(key,nsems,semflg)蘸拔;key:表示命名信號(hào)量IPC_PRIVATE,key_t ftok(const char *fname,int fd)环葵;fname:已存在的文件路徑调窍;id:表示子序號(hào),1--255张遭;nsems:信號(hào)量數(shù)目邓萨,0表示獲取信號(hào)量指定為0,非0新建的信號(hào)量數(shù)量菊卷;semflag:IPC_CREAT缔恳,信號(hào)量已經(jīng)存在不出錯(cuò),IPC_CREAT | IPC_EXCL洁闰,信號(hào)量已存在出錯(cuò)歉甚,權(quán)限建議使用八進(jìn)制數(shù)字;返回值:非負(fù)整數(shù)扑眉,信號(hào)量標(biāo)識(shí)铃芦,-1表示失敗襟雷;
semcreate.c
#include <stdio.h>
#include <unistd.h>
#include <sys/sem.h>
int main(int argc,char* argv[]){
key_t key = ftok(argv[1],1);
if(-1 == semget(key,1,IPC_CREAT|0644)){
perror("semget err");
return 1;
}
}
信號(hào)量操作:int semop(int semid,struct sembuf *sops,size_t nsops)刃滓;semid:表示信號(hào)量標(biāo)識(shí);sops:信號(hào)量結(jié)構(gòu)體耸弄,sem_num:信號(hào)量下標(biāo)咧虎,從0開(kāi)始,sem_flg:SEM_UNDO:表示在進(jìn)程結(jié)束時(shí)计呈,相應(yīng)的操作將會(huì)被取消砰诵,進(jìn)程沒(méi)有釋放該信號(hào)量而終止時(shí)操作系統(tǒng)釋放信號(hào)量征唬;0:表示的是默認(rèn)的選項(xiàng);IPC_NOWAIT:表示非阻塞狀態(tài)茁彭;sem_op:-1表示P操作总寒,1:表示V發(fā)送操作;nsops:semops大欣矸巍摄闸;
race.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <unistd.h>
void sem_p(int semid){
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = 0;
semop(semid,&buf,1);
}
void sem_v(int semid){
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = 0;
semop(semid,&buf,1);
}
union semun{
int val;
};
int main(int argc,char * argv[]){
int semid = semget(IPC_PRIVATE,1,IPC_CREAT|0644);
union semun un = {1};
if(-1 == semctl(semid,0,SETVAL,un)){
perror("semctl err");
return 1;
}
if(-1 == semid){
perror("semget err");
return 1;
}
fork();
int i=0;
for(;i<5;i++){
sem_p(semid);
printf("PID:%d,enter\n",getpid());
sleep(1);
printf("PID:%d,do something\n",getpid());
printf("PID:%d,leave\n",getpid());
sem_v(semid);
}
}
信號(hào)量控制:int semctl(semid, nsem,cmd,...);semid:信號(hào)量標(biāo)識(shí)妹萨;nsem:信號(hào)量下標(biāo)年枕;cmd:SETVAL,用于設(shè)置信號(hào)量的值乎完;GETVAL熏兄,獲取信號(hào)量的值;IPC_RMID树姨,表示刪除信號(hào)量的值摩桶;...:union semnum;
設(shè)置信號(hào)量的初始值semctl(smeid,信號(hào)量下標(biāo),SETVAL帽揪,semnum)硝清;
union semun {
int val;
struct semid_ds *buf;
unsigned short *arry;
};
刪除信號(hào)量:semctl(semid,信號(hào)量下標(biāo)台丛,IPC_RMID)耍缴;
semrmid.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/sem.h>
int main(int argc,char* argv[]){
key_t key = ftok(argv[1],1);
int semid;
if((semid = semget(key,0,O_RDWR))==-1){
perror("semget err");
return 1;
}
if(-1 == semctl(semid,0,IPC_RMID)){
perror("semctl err");
return 1;
}
}
查看使用ipcs命令砾肺;
需要注意的幾點(diǎn)是:
1挽霉、ftok()首個(gè)參數(shù)必須是已存在的路徑名;
2变汪、使用XXget()創(chuàng)建時(shí)侠坎,必須是使用IPC_CREAT,而不是O_CREAT
3裙盾、讀寫非阻塞的操作必須是設(shè)置在open打開(kāi)的操作中实胸;
Posix:優(yōu)先級(jí)高的先出;
System V:當(dāng)mtype小于0時(shí)番官,小于mtype絕對(duì)值的消息中庐完,最小的先出;0最先進(jìn)入的先出徘熔;>0