您的位置:首页 > 运维架构 > Linux

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

2014-11-22 10:53 281 查看
先上题目吧:

准备一个大于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);
}



然后上上代码中所用到的函数的详细解析













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



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息