一个例子入门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.共享内存的同步
先上源码吧,然后一句一句分析:
然后上上代码中所用到的函数的详细解析
最后读者可以自行写一下写文件进程的代码,可以向我索取
准备一个大于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); }
然后上上代码中所用到的函数的详细解析
最后读者可以自行写一下写文件进程的代码,可以向我索取
相关文章推荐
- VB Api简单入门(2)-一个简单的例子
- Spring 入门(一个简单的例子)--适合初学者
- 一个网上简单的EJB入门例子
- CTDP linux 程序员手册 C和C++编程(12)一个 Linux 串口测试例子
- LINUX下的一个SOCKET编程的例子
- Berkeley DB -- 入门知识和一个小例子
- Berkeley DB(一) -- 入门知识和一个小例子
- struts+hibernate+spring一个入门的实用例子
- Linux下多线程编程与信号处理易疏忽的一个例子
- 一个经典的ADO.NET入门例子
- 与afreez一起学习DirectFB之:一个linux下的framebuffer例子的学问
- 与afreez一起学习DirectFB之:一个linux下的framebuffer例子的学问
- 一个简单的linux下网络程序实例-网络编程入门
- Linux下多线程编程与信号处理易疏忽的一个例子 推荐
- 一个经典的ADO.NET入门例子
- Linux下,使用C/C++编写"静态链接库"的一个简单例子
- linux脚本编程快速入门-例子+基本语法
- CTDP linux 程序员手册 (4.6) 一个循环脚本的例子
- struts+hibernate+spring一个入门的实用例子(上)
- 一个简单的AJAX入门例子