消息隊列
消息隊列是在內核中實現的,并且是具有一定的優先級的一種進程間通信模型
POSIX PIC消息隊列
在unpv22e,ch 5.1--5.5可以查看這些知識,POSIX消息隊列使用的頭函數是mqueue.h;使用的庫文件為librt.so;消息隊列通過結構體:struct mq_arrt 來定義消息隊列屬性,結構體中選項包含的有:mq_flags:標志,在mq_open時被初始化,mq_setattr可以進行設置;這個值通常為0或者O_NONBLOCK;mq_maxmsg:表示的是隊列中消息的最大個數,只能在mq_open時被初始化;mq_msgsize:表示隊列中每個消息的最大值;mq_curmsgs:表示當前隊列消息長度,在mq_getattr 時進行獲取;
關于消息隊列的八種操作:
?創建消息隊列:mqd_t mq_open(const char *name, int oflag,mode_t mode,struct mq_attr *attr);name:表示posix IPC名字;oflag:表示標志,O_CREAT:表示在沒有時,創建該對象;O_EXCL:表示如果O_CREAT指定,但是name不存在,就返回錯誤信息;O_NONBLOCK:表示以非阻塞方式打開消息隊列;O_RDONLY:表示只讀;O_RDWR:表示讀寫;O_WRONLY:表示只寫;mode:權限:S_IWUSR:表示用戶屬主寫權限;S_IRUSR:表示用戶屬主讀權限;S_IWGRP:表示組成員寫權限;S_IRGRP:表示組成員讀權限;S_IWOTH:其他用戶寫權限;S_IROTH:表示其他用戶讀權限;attr:表示隊列屬性:attr.mq_falg = 0;表示阻塞;attr.mq_flag = NONBLOCK,表示非阻塞;返回值:-1,表示出錯;返回值為其他表示消息隊列描述符;
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;
}
}
刪除消息隊列: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");
}
打開消息隊列:mqd_t mq_open(const char *name,int oflag);name:posix IPC表示名字;oflag:表示標志位,O_RDONLY,只讀;O_RDWR:表示讀寫;O_WRONLY:表示只寫;返回值為-1時表示出錯,返回值為其他表示描述符;
隊列的打開函數一般和發送或者接收一起出現,就寫在一個函數里面;
?關閉消息隊列:int mq_close(mqd_t mqdes);其中mqdes表示消息隊列描述符;返回值-1表示出錯,0表示成功;
?設置消息隊列屬性:int mq_setattr(mqd_t mqdes,struct mq_attr *newattr,struct mq_attr *oldattr);mqdes:表示消息隊列描述符;newattr:用于設置新屬性,但是只能用于設置mq_falgs,其中0表示阻塞,NONBLOCK表示非阻塞;
oldattr:表示用于設置舊屬性;函數返回值-1表示出錯,返回值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);
}
獲取消息隊列屬性:int mq_getattr(mqd_t mqdes, struct mqdes,struct mq_attr *attr);mqdes:表示消息隊列描述符;attr:表示屬性信息;返回值:-1表示出錯信息;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);
}
發送消息:int mq_send(mqd_t mqdes,const char *msg_ptr,size_t msg_len,unsigned msg_prio);msg_ptr:表示消息隊列的指針;msg_len:表示消息長度,但是不能大于屬性值mq_msgsize的值;msg_prio:表示優先級,消息在隊列中將按照優先級大小順序來排列消息;如果消息隊列已滿,mq_send()函數將阻塞,知道油客埇的空間再次允許放置消息;如果O_NONBLOCK被指定,mq_send()那么將不會被阻塞,而是返回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:表示消息隊列的指針;msg_len:表示消息長度,不能夠大于屬性值mq_msgsize的值;msg_prio:表示優先級,消息在隊列中將按照優先級大小順序來排列消息;返回值:-1表示出錯,正數表示接收到消息的長度;如果隊列為空,mq_receive()函數將阻塞,知道消息隊列中有新的消息。如果O_NONBLOCK被指定,mq_receive()將不會阻塞,而是返回EAGAIN錯誤;
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);
}
對于共享內存的查看:man mq_overview,ls /dev/mqueue;cat /dev/mqueue/PIC名字;
POSIX共享內存
需要包含的頭文件sys/mman.h 需要包含的庫文件是librt.so
創建共享內存:int shm_open(const char *name,int oflag,mode_t mode);name:表示posix IPC的名字;ofloag:表示標志,O_CREAT:表示沒有的話,創建該對象;
O_EXCL:如果O_CREAT指定,但是name不存在,就返回錯誤;O_RDONLY:表示只讀;O_RDWR:表示讀寫;O_TRUNC:表示如果存在就截斷;mode:表示權限:S_IWUSR:表示用戶/屬主寫權限;S_IRUSR:表示用戶/屬主讀權限;S_IR、WGRP:表示組成員寫權限;S_IRGRP:表示組成員讀權限;S_IWOTH:表示其他用戶寫權限;S_IROTH:表示其他用戶讀權限;函數的返回值-1表示出錯;返回值為其他表示共享內存描述符;
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表示出錯,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]);
}
修改文件的大?。篿nt fruncate(int fd, off_t lenght),fd:表示文件描述符;length:表示文件大小,如果原來的文件帶下比參數length大,超過的部分就會被刪除;返回值:0表示成功;-1:失敗;這個函數用戶設置共享內存的大小,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:是一個結構體,里面的參數分別表示:st_mode:表示文件對應的模式,文件,目錄等;st_size:表示普通文件,對應的文件字節數;st_atime:文件最后被訪問的時間;st_mtime:文件最后被修改訪問的時間;st_ctime:文件狀態改變的時間;st_uid:文件所有者;st_gid:文件所有者對應的組;st_blksize:文件內容對應的塊大??;st_blksize:文件內容對應的塊大?。籹t_blocks:內容對應的塊數量;st_ino:inode節點號;st_dev:設備號碼;st_rdev:特殊設備號碼;st_nlink:文件的連接數;
?st_mode:S_IFREG:表示一般文件;S_IFDIR:表示目錄;S_IFSOCK:表示socket文件;S_IFIFO:表示先進先出;S_IFLINK:表示符號鏈接;S_IFCHR:表示字符設置;可以使用這些宏定義來判斷文件的類型;S_ISLINK(st_mode),S_ISREG(st_mode):判斷是否為一般文件;S_ISDIR(st_mode):判斷是否為目錄;S_ISCHR(st_mode):判斷是否為字符文件;S_ISBLK(st_mode):判斷是否為先進先出文件;S_ISSOCK(st_mode):判斷是否為socket;S_IFMT:文件類型的位遮罩;S_IFBLK:區塊裝置;S_IUID:文件的(set user-id on execution)位;S_ISGID:文件的(set group-id on execution);S_ISVTX:文件的sticky位;
?st_size:表示文件的大?。籹t_uid:表示屬主ID;st_uid:屬主ID;st_guid:表示組ID;
?返回值:0表示成功;-1表示失??;
暫時沒有代碼文件;
?建立內存映射:void * mmap(void * start,size_t length, int prot,int flags, int fd, off_t offset):start:映射區的開始地址,參數如果設置成NULL,表示有系統設置映射區的起始地址,如果考慮系統的可移植性,必須設置成為NULL;lenght:表示映射區的長度,單位是字節,但不足一頁按照一頁內存進行處理;prot:內存保護裝置 ;PROT_EXEC:表示頁內容可以被執行;PROT_READ:表示頁內容可以被讀?。籔ROT_WAITE:表示頁面內容可以被寫入;PROT_NONE:表示頁面內容不可以被訪問;但是不能夠與文件的打開模式沖突;flags:映射對象的類型,MAP_SHARED:表示變動共享;MAP_PRIVATE:表示變動私有;MAP_ANON:匿名內存映射;fd:文件描述符,不能使套接字和中斷的fd,-1表示匿名內存映射;
off_toset:表示被映射對象內容的起點;返回值:MAP_FAILED:表示失??;非MAP_FAILED:表示共享內存地址;
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);
}
刪除內存映射int munmap(void *start,size_t length);start:映射內存起始地址;length:表示內存大小;返回值:0表示成功,-1表示失?。恍枰⒁獾氖顷P閉mmap中的文件描述符不能刪除內存映射;
#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);
}
同步操作:int msync(void * addr,size_t len,int flags);addr:表示映射內存起始地址;len:表示內存大?。籪lags:表示同步參數,MX_ASYNC,調用會立即返回,不等到跟新的完成,MS_SYNC:表示同步,調用會等到更新完成之后返回;MS_INVALIDATE:通知使用該共享區域的進程,數據已經改變;在共享內容更改之后,是的文件的其他映射失效;返回值:0:表示成功;-1表示失敗;和文件的fflush相似;
?查看:man shm_overview;ls /dev/shm;注意的是msg_open默認生成共享內存的大小是0,需要ftuncate設置大小;
POSIX信號量
資料可以查看unv22e,頭文件是semaphore.h需要鏈接的庫文件是pthread;信號量類似于停車場的電子牌,信號量可以分為二值信號量,0和1;計數信號量0和n;信號量適用于控制多進程訪問共享資源的;
?信號:P信號:0表示掛起進程;>0時,減1;V信號:0表示恢復進程;>0:表示加1;信號的本質是在任一時刻只能有一個進程訪問臨界區;
命名信號量/基于文件
創建:sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);name:信號量IPC 名字;oflag:O_CREAT:如果沒有這些對象就創建這個對象;O_EXCL:如果O_CREAT指定,但是name不存在,就返回錯誤;mode:表示權限位;value:信號量初始值;返回值:非SEM_FAILED:信號量的指針;SEM_FAILED:出錯;
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);
}
}
打開:sem_t *sem_open(const char *name,int oflag);sem_t *sem_open(const char *name,int oflag):name:信號量IPC名字;oflag:0;返回值:非SEM_FAILED:信號量的指針;SEM_FAILED:出錯;
#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);
}
}
關閉:int sem_close(sem_t *sem);sem:信號量的指針;返回值:-1表示出錯,0表示成功;
刪除int sem_unlink(const char *name);name:表示信號量IPC的名字;返回值-1出錯,0表示成功;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
無名信號量/基于內存
初始化:int sem_init(sem_t *sem,int pshared,unsigned int value);sem:表示信號量的指針;pshared:表示共享方式,0表示線程間共享,1表示進程間共享,但是需要共享內存;value:信號量初始值;返回值:-1,出錯,-表示成功;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
銷毀:int sem_destory(sem_t *sem),sem:表示信號量的指針;返回值位1表示出錯,0表示成功;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
掛出:int sem_post(sem_t *sem);sem:信號量的指針;返回值:-1表示出錯,0表示成功;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
等待:int sem_wait(sem_t *sem);sem:表示信號量的指針;返回值:-1表示出錯,0表示成功;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
嘗試等待:int sem_trywait(sem_t *sem);sem:信號量的指針;返回值:-1表示出錯,0表示成功;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
獲取信號量的值:int sem_getvalue(sem_t *sem,int *sval);sem:信號量的指針;sval:信號量的值;返回值:0表示成功,-1表示出錯;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
查看man sem_overview
?標識/名字,路徑名 /tmp.123
幾種方式的對比:
創建:文件:mqd_t mq_open(const char *name,int oflag,mode_t mode);消息隊列:mqd_t mqopen(const char *name,int oflag,mode_t mode,struct mq_arrt, *attr)共享內存:int shm_open(const char *name,int oflag,mode_t);信號量:sem_t *sem_open(const char *name,int oflag,mode_t mode,unsigned int value);
刪除:文件:int unlink(const char *name);消息隊列:mqd_t mq_unlink(const char *name);共享內存:int shm_unlink(const char *name) 信號量:sem_t *sem_unlink(const char *name);
System V PIC
system V消息隊列
需要包含的頭文件是sys/msg.h,需要自定義的結構體msgbuf,其中包含兩個選項:消息類型:必須是long,必須是結構體的第一個變量,mtext:標識消息數據,可以隨意定義;
相關函數
消息獲?。篿nt msgget(key_t key, int msgflg);key:IPC鍵,key_t ftok(char *path,int id),path,id;IPC_PRIVATE:通常用于親緣進程;msgflg:IPC_CREAT:標識創建;IPC_CREAT | IPC_EXCL;權限:建議使用八進制數字來進行描述;返回值非負整數標識消息隊列標識,-1:標識失?。?br> 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);
}
消息發送:int msgsnd(int msgid,const void *msgptr,size_t msgsz,int msgflg);msgid:表示消息隊列標識;msgptr:表示消息結構體,是以一個長整型成員變量開始的結構體,
struct test_messsge{
long mtype; //must > 0
char mtext;// data;
};
msgsz:表示消息隊列長度,但是不包括長整型變量;msgflg:用于控制函數的行為,0表示忽略;IPC_NOWAIT:表示如果消息隊列為空,就返回一個ENOMSG,并將控制權教會個調用函數的進程。MSG_NOERROR:如果函數取得的消息長度大于msgsz,將只返回msgsz的長度,剩下的部分就被丟棄了。MSG_EXCEPT:當msgtyp > 0時,接受的類型不扥估msgtype的第一條消息;返回值:表示成功,-1表示失?。?br> 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:表示消息隊列標識;msgptr:消息結構體,以一個長整型成員變量開始的結構體;
struct test_message{
long int message_type; // the data you which to transfer;
};
msgtype:標識消息的接收類型,0標識消息隊列中的第一個消息,大于0標識獲取具有相同消息類型的第一個消息;小于0標識獲取類型等于或者小于msgtype的絕對值的最小一個消息;msgflg:用于控制函數的行為,0標識忽略,IPC_NOWAIT:如果消息隊列為空則返回一個ENOMSG,并將控制權返回給調用函數的進程;MSG_NOERROR,如果函數取得的消息隊列長度大于msgsz,將只返回msgsz長度的信息,剩下的部分機會被丟棄;MSG_EXCEPT:當msgtype > 0 時,接受的類型不等于msgtype的第一個條消息;返回值:0標識接收到的消息長度,-1失?。?br> 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:消息隊列標識符;IPC_STAT:獲取當前消息隊列控制信息;IPC_SET:設置當前消息隊列控制信息;IPC_RMID:刪除消息隊列;buf:消息隊列的模式結構,msg_perm.mode:表示消息隊列讀寫模式;msg_qbytes:隊列最大大??;msg_cbytes:當前隊列的大?。籱sg_qnum:表示當前隊列的消息數;返回值:0表示成功,-1表示失??;
msgctl.c:標識用于刪除消息
#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);
}
}
對于消息隊列的查看可以使用ipcs來進行查看;
System V 共享內存
資料查看unpv22e,ch14,頭文件sys/shm.h
相關的函數
共享內存的獲?。篿nt shmget(key_t key, size_t size, int shmflg);key:命名共享內存IPC_PRIVATE,key_t ftok(const char *fname,int fd);fname:標識已經存在的文件路徑,id:表示子序號1--255;size:表示內存容量,非0表示新建的共享內存大小,0表示獲取共享內存指定為0;shmflg:IPC_CREAT:用于創建共享內存;IPC_CREAT | IPC_EXCL;權限:建議使用八進制數字來表示;返回值:非負整數,表示共享內存表示符,-1表示失?。?br> 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;
}
共享內存鏈接:void *shmat(int shmid,const void *shmaddr,int shmflg);shmid:共享內存標識符;shmaddr:指定共享內存連接到當前及才能拿中的地址位置;通常設置為NULL,表示讓系統來選擇共享內存的地址,這點是出于兼容性考慮;shmflg:表示標志位,SHM_RDONLY,只讀,0表示讀寫;返回值:非負整數表示共享內存指針,-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;
}
共享內存分離:int shmdt(const void *shmaddr);shmaddr:表示共享內存指針;返回值0表示成功,-1表示失?。?/p>
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
共享內存控制:int shmctl(int shmid,int cmd,struct shmid_ds *buf);shmid:共享內存標識符;cmd:IPC_STAT,獲取當前共享內存控制信息;IPC_SET:設置當前共享內存控制信息;IPC_RMID:刪除共享內存;buf:共享內存信息結構:int shm_segsz,表示共享內存大小,shm_perm.mode:表示讀寫權限;返回值:0表示成功,-1表示失?。猾@取共享內存大小,shmctl(shmid,IPC_STAT,&buf);buf.shm_segsz;刪除共享內存: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;
}
}
共享內存也可以使用ipcs進行查看;
System V信號量
&38195;unpv22e,ch11;頭文件是:、sys/sem.h
相關函數
信號量的獲?。篿nt semget(key,nsems,semflg);key:表示命名信號量IPC_PRIVATE,key_t ftok(const char *fname,int fd);fname:已存在的文件路徑;id:表示子序號,1--255;nsems:信號量數目,0表示獲取信號量指定為0,非0新建的信號量數量;semflag:IPC_CREAT,信號量已經存在不出錯,IPC_CREAT | IPC_EXCL,信號量已存在出錯,權限建議使用八進制數字;返回值:非負整數,信號量標識,-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;
}
}
信號量操作:int semop(int semid,struct sembuf *sops,size_t nsops);semid:表示信號量標識;sops:信號量結構體,sem_num:信號量下標,從0開始,sem_flg:SEM_UNDO:表示在進程結束時,相應的操作將會被取消,進程沒有釋放該信號量而終止時操作系統釋放信號量;0:表示的是默認的選項;IPC_NOWAIT:表示非阻塞狀態;sem_op:-1表示P操作,1:表示V發送操作;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);
}
}
信號量控制:int semctl(semid, nsem,cmd,...);semid:信號量標識;nsem:信號量下標;cmd:SETVAL,用于設置信號量的值;GETVAL,獲取信號量的值;IPC_RMID,表示刪除信號量的值;...:union semnum;
設置信號量的初始值semctl(smeid,信號量下標,SETVAL,semnum);
union semun {
int val;
struct semid_ds *buf;
unsigned short *arry;
};
刪除信號量:semctl(semid,信號量下標,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命令;
需要注意的幾點是:
1、ftok()首個參數必須是已存在的路徑名;
2、使用XXget()創建時,必須是使用IPC_CREAT,而不是O_CREAT
3、讀寫非阻塞的操作必須是設置在open打開的操作中;
Posix:優先級高的先出;
System V:當mtype小于0時,小于mtype絕對值的消息中,最小的先出;0最先進入的先出;>0