一个例子入门Linux进程间通信

先上题目吧:

准备一个大于10M的文件。
编写两个独立的程序file_read.c和file_write.c。
file_read负责打开文件,每次从文件读入128-1024个字节(随机产生),放入到共享内存区;共享内存区最大为1024字节。
file_write负责从共享内存中接收数据,并写入到另一个文件中。
file_read通过消息通知file_write每次写入共享内存的字节数。双方通过信号量进行同步。


先来聊聊Linux下进程间通信的方式



初的UNIX的进程通信:包括管道和信号
System V进程间通信(IPC):包括System V消息队列、System V信号量以及System V共享内存区。
Posix 进程间通信(IPC):包括Posix消息队列、Posix信号量以及Posix共享内存区。
基于套接字的进程间通信:就是Socket,应用于网络中不同机器之间的通信

消息队列是消息的链接表。它克服了前两种通信方式中信息量有限的缺点,具有写权限的进程可以按照一定的规则向消息队列中添加新消息;对消息队列有读权限的进程则可以从消息队列中读取消息。
共享内存:可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种通信方式需要依靠某种同步机制,如互斥锁和信号量等。
         

先仔细分析一下这个题目中要使用到的进程间通信技术
1.消息队列
2.共享内存
3.共享内存的同步

先上源码吧,然后一句一句分析:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include<errno.h>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<fcntl.h>
#include<time.h>

struct message           //发送的消息的结构体,一般是自己定义,但是必须以long 开头,下面消息的正文标准是char型数组,但实际上也可以自定义
{
	long msg_type;   //消息的类型
	short msg_data;  //消息的正文
};

union semun              //此结构体在信号量的删除的时候会使用
{ 
        int val; 
	struct semid_ds *buf; 
	unsigned short int *array;
        struct seminfo *__buf; 
};

int semaphore_v(int semid)                  //即P操作
{
	struct sembuf sem_b;                //sembuf已经在sys/sem.h中定义
	sem_b.sem_num = 0;                  //信号量编号,使用单个信号时,常取值为0
 	sem_b.sem_op = 1;                   //信号量操作,取值为-1时表示P操作,为1时表示V操作	if(semop(semid, &sem_b, 1) == -1)  //信号量的操作函数,参数1为信号量标识符,常是semget()函数的返回值,参数3为操作数组
	{                                   //&sem_b中操作个数(元素数目),常取值为一,此函数出错返回-1
		printf("%s\n",strerror(errno));
 		return 0;
	}	
	return 1;
 }

int semaphore_p(int semid)                   //同上
{
	struct sembuf sem_b;
 	sem_b.sem_num = 0;
	sem_b.sem_op = -1;
	if(semop(semid, &sem_b, 1) == -1)
	{
		printf("%s\n",strerror(errno));
		return 0;
	}
	return 1;
}

void clearBuf(char *combuff)                  //清空共享内存,应该不难理解
{
	int i;
	for(i=0;i<1024;i++)
	combuff[i]='\0';
}

int main(int argc,char **argv)
{
	int fd;                    //文件描述符
	int qid;                   //消息队列标识符
	key_t key;                 //ipc键值,没有它就没有ipc
	int semid;                 //信号量描述符
	int shmid;                 //共享内存描述符
	char *combuff;             //指向共享内存的指针
	int tempNo;               
	int temp;
	struct message msg;        //消息结构体

	if(argc!=2)                //如果没有输入读文件路径,直接退出
	{
		printf("please input the path of testData!\n");
		exit(1);
	}

	if((fd=open(argv[1],O_RDONLY))==-1){       //打开文件
		perror("open");
		exit(1);
	}
	printf("fd %d\n",fd);

	if((key=ftok(".",'a'))==-1){               //用已知存在的路径生成ipc键值,如果两个或者多个进程使用ftok()的参数相同,则产生的键值相同
		perror("ftok");                    //键值相同是进程间通信的基础
		exit(1);
	}
	printf("key %d\n",key);

	if((qid=msgget(key,IPC_CREAT|0666))==-1){  //取得消息队列描述符
		perror("msgget");
		exit(1);
	}
	printf("qid %d\n",qid);

	if((shmid=shmget(key,1024,IPC_CREAT|0777))==-1){ //取得共享内存描述符
		perror("shmget");
		exit(1);
	}
	printf("shmid %d\n",shmid);

	combuff=(char *)shmat(shmid,NULL,0);        //将指针指向操作系统分配的共享内存首地址
	if((int)combuff==-1){
		perror("shmget");
		exit(1);
	}

	if((semid=semget(key,1,IPC_CREAT|0666))==-1){//获取信号量
		perror("shmget");
		exit(1);
	}
	printf("semid %d\n",semid);

	srand(time(0));                              //种下种子,以便后面产生随机数
	do
	{
		tempNo=rand()%897+128;               //产生随机数

	    	semaphore_p(semid);                  //在对共享内存操作之前先上锁
		clearBuf(combuff);
		temp=read(fd,combuff,tempNo);
		semaphore_v(semid);                  //操作完成之后释放锁
		
		msg.msg_data=temp;                   //填充消息结构体
		msg.msg_type = getpid(); 
	
		if((msgsnd(qid,&msg,sizeof(short),0))<0){  //发送消息
			perror("message posted");
			exit(1);
		}
		while(strlen(combuff)!=0&&temp!=0);   //等待读取端取走共享内存里面的数据(读取端读取数据后会将共享内存清空)
                                                      //此等待可以防止共享内存里面的数据被覆盖,导致写入的文件数据不完整
	}while(temp!=0);
	exit(0);
}
 
 
然后上上代码中所用到的函数的详细解析

最后读者可以自行写一下写文件进程的代码,可以向我索取



  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值