进程间通信——消息队列,共享内存,信号量数组

命令:ipcs 查看共享内存、消息队列、信号量数组使用情况
ipcrm:删除 大写(根据指定的KEY删除) 小写(根据指定的id删除)

|共享内存 |消息队列|信号量数组
|-M|-Q|-S
|-m|-q|-s

在这里插入图片描述
三种通信方式键值KEY获取:
ftok()函数:key_t ftok(const char *pathname, int proj_id);
xxxget xxxopt xxxctl

消息队列

具有缓存消息的能力:ulimit -a 查看POSIX MESSAGE QUEUES参数
1.创建:int msgget(key_t key, int msgflg);
2.使用(双工): msgop:
发送 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
接收 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数2:接收的内存空间位置,该空间定义为一个的结构体msg_st
参数3:接收的数据字节
参数4:是否挑选消息接收
参数5:有无特殊要求
3.控制:msgctl int msgctl(int msqid, int cmd, struct msqid_ds *buf); cmd参数来决定消息队列的控制命令

协议设置proto.h

#ifndef PROTO_H__
#define PROTO_H__

#define KEYPATH "/home/rubylee/Desktop/process/communication/msg"//key_t ftok中的路径参数
#define KEYPROJ 'g'//key_t ftok函数中整型数
#define NAMESIZE 32
struct msg_st//数据结构体
{
long mtype;//消息的类型
char name[NAMESIZE];
int math;
int chinese;
};
#endif

发送程序(主动端:先发包的一方)send.c

#include<stdio.h>
#include<stdlib.h>
#include "proto.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
int main()
{
key_t key=ftok(KEYPATH,KEYPROJ);//创建key值
if(key<0) {perror("ftok failed");exit(1);}

int msgid=msgget(key,0);//创建消息队列 得到msgid
if(msgid<0)
{
perror("msgget failed");
exit(1);

}
struct msg_st sbuf;
sbuf.mtype=1;
strcpy(sbuf.name,"rubylee");
sbuf.math=rand()%100;//随机设置值
sbuf.chinese=rand()%100;//随机设置值
if(msgsnd(msgid,&sbuf,sizeof(sbuf)-sizeof(long),0)<0)
{
perror("msgsnd failed");
exit(1);
}

puts("send ok!");

exit(0);
}

接收程序(被动端:先运行)rev.c

#include<stdlib.h>
#include "proto.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
int main()
{
        struct msg_st rbuf;//接收数据缓存
      key_t key=ftok(KEYPATH,KEYPROJ);
        if(key<0)
        {
        perror("ftok failed");
        exit(1);
        }
        int msgid=msgget(key,IPC_CREAT|0600);//IPC_CREAT创建  0600权限 第一位是gid或者uid  后面是owner,group,other的权限
        if(msgid<0)
        {
        perror("msgget failed");
        exit(1);
        }
      while(1){
        if(msgrcv(msgid,&rbuf,sizeof(rbuf)-sizeof(long),0,0)<0)
        sizeof(rbuf)-sizeof(long)减去了消息类型声明的long类型即:传入数据量大小
        {perror("msgrcv failed");exit(1);}
        printf("NAME=%s\n",rbuf.name);
        printf("chinese=%d\n",rbuf.chinese);
        printf("math=%d\n",rbuf.math);
       //加入信号机制实现正常终止
      }
        msgctl(msgid,IPC_RMID,NULL);//销毁实例
        exit(0);
}
                    

信号量数组

本质:计数器 主要用来控制多个进程对共享资源的使用
1.创建函数semget int semid=semget(key_t key, int nsems, int semflg);
参数1:key值 设置为IPC_PRIVATE时 代表亲缘关系的进程通信
参数2:信号量数组长度
参数3:IPC_CREATE和权限
2.信号量控制函数semctl:
int semctl(int semid, int semnum, int cmd, …);
参数2:semnum的下标值
参数3cmd:
SETVAL 设置单个信号量的值
GETALL 返回信号量集合中所有信号量的值
IPC_RMID删除指定的信号量集合
3.semopt函数实现pv操作:
int semop(int semid, struct sembuf *sops, size_t nsops);
参数2:结构体数组地址

在这里插入图片描述

1.文件锁程序

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define PROCNUM 20
#define FNAME "/tmp/out"
#define LINESIZE 1024

static void func_add(void)
{
FILE *fp;
int fd;
char linebuf[LINESIZE];
fp=fopen(FNAME,"r+");
        if(fp==NULL)
        {
        perror("fopen()");
        exit(1);
        }
fd=fileno(fp);//获得已经打开的文件描述符

lockf(fd,F_LOCK,0);//
//int lockf(int fd, int cmd, off_t 
//off_t锁定的连续字节数
fgets(linebuf,LINESIZE,fp);//读取一行字符串
fseek(fp,0,SEEK_SET);//相对偏移量查找子节数 SEEK_SET 文件头
sleep(1);
fprintf(fp,"%d\n",atoi(linebuf)+1);//atoi字符串转整型
fflush(fp);
lockf(fd,F_ULOCK,0);
fclose(fp);
return;
}
int main()
{
        pid_t pid;
        for(int i=0;i<PROCNUM;i++)
        {
        pid=fork();
                if(pid<0)
                {
                perror("fork()");
                  exit(1);
                }
                if(pid==0)
                {
                func_add();
                exit(0);
                }
        }
     for(int i=0;i<PROCNUM;i++)
        wait(NULL);
        exit(0);
}

2.采用信号量集对文件进行加锁和解锁

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<errno.h>
#define PROCNUM 20
#define FNAME "/tmp/out"
#define LINESIZE 1024
static int semid;
static void P(void)
{
        struct sembuf op;
        op.sem_num=0;
        op.sem_op=-1;//资源量-1
        op.sem_flg=0;//无特殊要求
        while(semop(semid,&op,1)<0)
        {
           if(errno!=EINTR||errno!=EAGAIN)
                {
                perror("semop()");
                exit(1);
                }

        }


}
static void V(void)
{
        struct sembuf op;
        op.sem_num=0;//信号数组下标
        op.sem_op=1;//资源量+1
        op.sem_flg=0;//无特殊要求
        if(semop(semid,&op,1)<0)
        {
                perror("semop()");
                exit(1);
        }

}

static void func_add(void)
{
FILE *fp;
int fd;
char linebuf[LINESIZE];
fp=fopen(FNAME,"r+");
        if(fp==NULL)
        {
        perror("fopen()");
        exit(1);
        }

P();//取资源量
fgets(linebuf,LINESIZE,fp);//读取一行字符串
fseek(fp,0,SEEK_SET);//相对偏移量查找子节数 SEEK_SET 文件头
sleep(1);
fprintf(fp,"%d\n",atoi(linebuf)+1);//atoi字符串转整型
fflush(fp);
V();//还资源量

fclose(fp);
return;

}
int main()
{
        pid_t pid;
        //key=ftok();//亲缘关系通信时 key值为ipc_private
         semid=semget(IPC_PRIVATE,1,0600);
        if(semid<0)
        {
        perror("semget()");exit(1);
        }
		/*设置下标0的互斥量的资源总量为1*/
        if(semctl(semid,0,SETVAL,1) < 0)
        {
        perror("semctl()");
        exit(1);
        }
        
        for(int i=0;i<PROCNUM;i++)
        {
        pid=fork();
                if(pid<0)
                {
                perror("fork()");
                exit(1);
                }
                if(pid==0)
                {
                func_add();
                exit(0);
                }
        }
     for(int i=0;i<PROCNUM;i++)
        wait(NULL);
        semctl(semid,0,IPC_RMID);//销毁信号量
        exit(0);
}


结果
在这里插入图片描述

共享内存

创建:int shmid= shmget(key_t key, size_t size, int shmflg);
参数1:key值 匿名IPC时为IPC_PRIVATE(亲缘间进程通信)
参数2:共享内存大小
参数3:权限:0600 第一位是gid或者uid
内存映射: void *shmat(int shmid, const void *shmaddr, int shmflg);
参数2:映射到那块地址空间 NULL:自动分配
参数3:权限 只读? 只写? 读写? 无要求设置0
解除映射: int shmdt(const void *shmaddr);
参数:解除映射的地址空间
控制共享内存:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数2:IPC_RMID销毁共享内存
参数3:NULL

#include <sys/types.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>

#define MEMSIZE 1024
//#define BUFSIZE 1024
int main()
{
char *ptr;
int shmid=shmget(IPC_PRIVATE,MEMSIZE,0600);//匿名IPC
        if(shmid<0)
        {
        perror("shmget()");exit(1);
        }
pid_t pid=fork();
if(pid<0)
{
perror("pid()");exit(0);
}
if(pid==0)//child write
{
 ptr=shmat(shmid,NULL,0);
if(ptr==(void*)-1)
{
  perror("child shmat()");
exit(1);
}
strcpy(ptr,"hello!");//写入共享内存
shmdt(ptr);//解除映射
exit(0);
}
else//父进程读
  {
    wait(NULL);
    ptr=shmat(shmid,NULL,0);
    if(ptr==(void*)-1)
        {
        perror("parent shmat()");
        exit(1);
        }
        puts(ptr);//读共享内存
        shmdt(ptr);//解除映射
        shmctl(shmid,IPC_RMID,NULL);//销毁共享内存
   exit(0);
   }
                                                                                                                                                                                                  

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值