Linux-C-day-4-進程間通信-消息隊列||信號量 ||共享內存

消息隊列

消息隊列是在內核中實現的,并且是具有一定的優先級的一種進程間通信模型

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,517評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,087評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,521評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,493評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,207評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,603評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,624評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,813評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,364評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,110評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,305評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,874評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,532評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,953評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,209評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,033評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,268評論 2 375

推薦閱讀更多精彩內容

  • 進程間的通信主要分為本機器進程間的通信和不同機器間進程的通信。本文主要描述本機進程間的通信。 一、傳統Linux的...
    一葉之界閱讀 407評論 0 2
  • 儒家與鬼神 大拙 《論語·述而》有云: “子不語怪力亂神。”一般都理解為“孔子不談論怪異、勇力、叛亂和鬼...
    豬大拙閱讀 1,410評論 0 1
  • 想得到的,需要付出努力,但最終不一定得到。
    七根白發閱讀 163評論 0 0
  • 你是否遇到過這樣的困擾: 當你寫完一段代碼后,要看到效果,必須點擊IDEA的停止按鈕,然后再次重啟啟動項目,你是否...
    周小春閱讀 4,479評論 0 7
  • 美好晨光,有媽媽,有孩子,有一份工作
    其其菱菱閱讀 120評論 0 0