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]);
}

修改文件的大小:int 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:文件内容对应的块大小;st_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:表示文件的大小;st_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:表示页内容可以被读取;PROT_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表示失败;需要注意的是关闭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:表示内存大小;flags:表示同步参数,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:标识消息数据,可以随意定义;

相关函数

消息获取:int 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:标识失败;
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表示失败;
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失败;
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:当前队列的大小;msg_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

相关的函数

共享内存的获取:int 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表示失败;
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表示失败;

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

共享内存控制: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

相关函数

信号量的获取:int 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阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 进程间通信 进程间通信即IPC(InerProcess Communication)Unix ipc 已经是而且继...
    千里山南阅读 457评论 0 2
  • 进程间的通信主要分为本机器进程间的通信和不同机器间进程的通信。本文主要描述本机进程间的通信。 一、传统Linux的...
    一叶之界阅读 393评论 0 2
  • 儒家与鬼神 大拙 《论语·述而》有云: “子不语怪力乱神。”一般都理解为“孔子不谈论怪异、勇力、叛乱和鬼...
    猪大拙阅读 1,365评论 0 1
  • 想得到的,需要付出努力,但最终不一定得到。
    七根白发阅读 105评论 0 0
  • 你是否遇到过这样的困扰: 当你写完一段代码后,要看到效果,必须点击IDEA的停止按钮,然后再次重启启动项目,你是否...
    周小春阅读 4,401评论 0 7