进程间的通信方式通信问题需要解决哪几个问题

1220人阅读
Linux C(32)
进程间的通信方式:
&&&1.管道(pipe)及有名管道(named pipe):
&&&&管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
& &&有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
& &&<span style="color:#.信号(signal):
&&&&&信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
&&&3.消息队列(message queue):
&&&&消息队列是消息的链接表,它克服了上两种通信方式中信号量有限的缺点,具有写权限得进程可以按照一定得规则向消息队列中添加新信息;对消息队列有读权限得进程则可以从消息队列中读取信息。
& &其基本思想是:根据”生产者-消费者”原理,利用内存中公用消息缓冲区实现进程之间的信息交换. &
& &内存中开辟了若干消息缓冲区,用以存放消息.每当一个进程向另一个进程发送消息时,便申请一个消息缓冲区,并把已准备好的消息送到缓冲区,然后把该消息缓冲区插入到接收进程的消息队列中,最后通知接收进程.接收进程收到发送里程发来的通知后,从本进程的消息队列中摘下一消息缓冲区,取出所需的信息,然后把消息缓冲区不定期给系统.系统负责管理公用消息缓冲区以及消息的传递. &
& &一个进程可以给若干个进程发送消息,反之,一个进程可以接收不同进程发来的消息.显然,进程中关于消息队列的操作是临界区.当发送进程正往接收进程的消息队列中添加一条消息时,接收进程不能同时从该消息队列中到出消息:反之也一样. &
&&&4.共享内存(shared memory):
&&&&&可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。
&&&&这种通信模式需要解决两个问题:第一个问题是怎样提供共享内存;第二个是公共内存的互斥关系则是程序开发人员的责任。
&&&5.信号量(semaphore):
&&&&&主要作为进程之间及同一种进程的不同线程之间得同步和互斥手段。
&&&6.套接字(socket);
&&&&&套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
& &&1&管道&
  它包括无名管道和有名管道两种,前者用于父进程和子进程间的通信,后者用于运行于同一台机器上的任意两个进程间的通信。&
  1.1&无名管道由pipe()函数创建:&
#include &unistd.h&
int pipe(int filedis[2]);//参数filedis返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开。filedes[1]的输出是filedes[0]的输入。
//下面的例子示范了如何在父进程和子进程间实现通信。&#define INPUT 0 #define OUTPUT 1 void main()&{ &&&&int file_descriptors[2];
&&&&/*定义子进程号 */ &&&&pid_t pid; &&&&char buf[256]; &&&&int returned_count;
&&&&/*创建无名管道*/ &&&&pipe(file_descriptors);
&&&&/*创建子进程*/ &&&&if((pid = fork()) == -1) { &&&&&&&&printf(&Error in fork\n&); &&&&&&&&exit(1); &&&&}
&&&&/*执行子进程*/ &&&&if(pid == 0) { &&&&&&&&printf(&in the spawned (child) process...\n&);
&&&&&&&&/*子进程向父进程写数据,关闭管道的读端*/ &&&&&&&&close(file_descriptors[INPUT]); &&&&&&&&write(file_descriptors[OUTPUT], &test data&, strlen(&test data&)); &&&&&&&&exit(0); &&&&}else{
&&&&&&&&/*执行父进程*/ &&&&&&&&printf(&in the spawning (parent) process...\n&);
&&&&&&&&/*父进程从管道读取子进程写的数据,关闭管道的写端*/ &&&&&&&&close(file_descriptors[OUTPUT]); &&&&&&&&returned_count = read(file_descriptors[INPUT], buf, sizeof(buf)); &&&&&&&&printf(&%d bytes of data received from spawned process: %s\n&, &&&&&&&&returned_count, buf); &&&&} }
& &&& &&1.2&有名管道可由两种方式创建
   方式一:mkfifo(&myfifo&,&rw&);&
   方式二:mknod myfifo p&
  &生成了有名管道后,就可以使用一般的文件I/O函数如open、close、read、write等来对它进行操作。
/* 进程一:读有名管道*/ #include &stdio.h& #include &unistd.h&
void main()&{ &&&&FILE * in_file; &&&&int count = 1; &&&&char buf[80];
&&&&in_file = fopen(&mypipe&, &r&); &&&&if (in_file == NULL) { &&&&&&&&printf(&Error in fdopen.\n&); &&&&&&&&exit(1); &&&&}
&&&&while ((count = fread(buf, 1, 80, in_file)) & 0) &&&&&&&&printf(&received from pipe: %s\n&, buf);
&&&&fclose(in_file); }
/* 进程二:写有名管道*/ #include &stdio.h& #include &unistd.h&
void main()&{ &&&&FILE * out_file; &&&&int count = 1; &&&&char buf[80];
&&&&out_file = fopen(&mypipe&, &w&); &&&&if (out_file == NULL) { &&&&&&&&printf(&Error opening pipe.&); &&&&&&&&exit(1); &&&&}
&&&&sprintf(buf,&this is test data for the named pipe example\n&); &&&&fwrite(buf, 1, 80, out_file);
&&&&fclose(out_file); }
& &&2 消息队列&
  &消息队列用于运行于同一台机器上的进程间通信,它和管道很相&#20284;,是一个在系统内核中用来保存消息的队列,它在系统内核中是以消息链表的形式出现。消息链表中节点的结构用msg声明。
& &&&&事实上,它是一种正逐渐被淘汰的通信方式,我们可以用流管道或者套接口的方式来取代它,所以,我们对此方式也不再解释,也建议读者忽略这种方式。&
 <span style="font-family:楷体; color:# 共享内存&
   &共享内存是运行在同一台机器上的进程间通信最快的方式,因为数据不需要在不同的进程间复制。通常由一个进程创建一块共享内存区,其余进程对这块内存区进行
& &&& &得到共享内存有两种方式:映射/dev/mem设备和内存映像文件。前一种方式不给系统带来额外的开销,但在现实中并不常用,因为它控制存取的将是
实际的物理内存,
   首先要用的函数是shmget,它获得一个共享存储标识符。&
    &#include &sys/types.h&&
    &#include &sys/ipc.h&&
     #include &sys/shm.h&&
& &&& &&& &&& &&&&int
shmget(key_t key, int size, int flag);&
   &这个函数有点类&#20284;大家熟悉的malloc函数,系统按照请求分配size大小的内存用作共享内存。 &
& &&&&&&&当共享内存创建后,其余进程可以调用shmat()将其连接到自身的地址空间中。&
& &&  &void *shmat(int shmid, void *addr, int flag);&
 & &&shmid为shmget函数返回的共享存储标识符,addr和flag参数决定了以什么方式来确定连接的地址,函数的返回&#20540;即是该进程数据段所连接的实际地址,进程可以对此进程进行读写操作。&
 && &&使用共享存储来实现进程间通信的注意点是对数据存取的同步,必须确保当一个进程去读取数据时,它所想要的数据已经写好了。通常,信号量被要来实现对共享存
储数据存取的同步,另外,可以通过使用shmctl函数设置共享存储内存的某些标志位如SHM_LOCK、SHM_UNLOCK等来实现。&
  &4 信号量&
  &信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是前一节的共享内存方式的进程间通信。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。一般说来,为了获得共享资源,进程需要执行下列操作:&
   (1) 测试控制该资源的信号量。&
   (2) 若此信号量的&#20540;为正,则允许进行使用该资源。进程将信号量减1。&
   (3) 若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量&#20540;大于0,进程被唤醒,转入步骤(1)。&
   (4) 当进程不再使用一个信号量控制的资源时,信号量&#20540;加1。如果此时有进程正在睡眠等待此信号量,则唤醒此进程。&
#include &sys/types.h& #include &sys/ipc.h& #include &sys/sem.h&
int semget(key_t key, int nsems, int flag); struct sem {
short sempid;/* pid of last operaton */
ushort semval;/* current value */
ushort semncnt;/* num procs awaiting increase in semval */
ushort semzcnt;/* num procs awaiting semval = 0 */}  
  && &&key是前面讲过的IPC结构的关键字,flag将来决定是创建新的信号量集合,还是引用一个现有的信号量集合。nsems是该集合中的信号量数。如果是创建新
集合(一般在服务器中),则必须指定nsems;如果是引用一个现有的信号量集合(一般在客户机中)则将nsems指定为0。&
   semctl函数用来对信号量进行操作。&
   int semctl(int semid, int semnum, int cmd, union semun arg);&
   不同的操作是通过cmd参数来实现的,在头文件sem.h中定义了7种不同的操作,实际编程时可以参照使用。&
& &&& &&&semop函数自动执行信号量集合上的操作数组。&
   int semop(int semid, struct sembuf semoparray[], size_t nops);&
   semoparray是一个指针,它指向一个信号量操作数组。nops规定该数组中操作的数量。
#include &stdio.h& #include &sys/types.h& #include &sys/sem.h& #include &sys/ipc.h& void main()&{ &&&&key_t unique_key; /* 定义一个IPC关键字*/ &&&&int id; &&&&struct sembuf lock_it; &&&&union semun options; &&&&int i; &&&&unique_key = ftok(&.&, 'a'); /* 生成关键字,字符'a'是一个随机种子*/ &&&&&&&&/* 创建一个新的信号量集合*/ &&&&id = semget(unique_key, 1, IPC_CREAT | IPC_EXCL | 0666); &&&&printf(&semaphore id=%d\n&, id); &&&&options.val = 1; /*设置变量&#20540;*/ &&&&semctl(id, 0, SETVAL, options); /*设置索引0的信号量*/ &&&&/*打印出信号量的&#20540;*/ &&&&i = semctl(id, 0, GETVAL, 0); &&&&printf(&value of semaphore at index 0 is %d\n&, i); &&&&/*下面重新设置信号量*/ &&&&lock_it.sem_num = 0; /*设置哪个信号量*/ &&&&lock_it.sem_op = -1; /*定义操作*/ &&&&lock_it.sem_flg = IPC_NOWAIT; /*操作方式*/
&&&&if (semop(id, &lock_it, 1) == -1) { &&&&&&&&printf(&can not lock semaphore.\n&); &&&&&&&&exit(1); &&&&} &&&&i = semctl(id, 0, GETVAL, 0); &&&&printf(&value of semaphore at index 0 is %d\n&, i); &&&&/*清除信号量*/ &&&&semctl(id, 0, IPC_RMID, 0); }
& & & & &可以使用系统调用semget()创建一个新的信号量集,或者存取一个已经存在的信号量集:
& & & & & & intsemget(key_t key,int nsems,int semflg);
& & &下面是一个打开和创建信号量集的程序:
intopen_semaphore_set(key_t keyval,int numsems){&&&&intsid;
&&&&if(!numsems)&&&&&&&&return(-1);
&&&&if((sid=semget(mykey,numsems,IPC_CREAT|0660))==-1)&&&&{&&&&&&&&return(-1);&&&&}
&&&&return(sid);}
& &&&&&&系统调用:semop();
& &&& &&调用原型:int semop(int semid,struct sembuf*sops,unsign ednsops);
& &&& &&返回&#20540;:0,如果成功。-1,如果失败:errno=E2BIG(nsops大于最大的ops数目)
系统调用:semctl();
原型:int semctl(int semid,int semnum,int cmd,union semunarg);
返回&#20540;:如果成功,则为一个正数。如果失败,则为-1:errno=EACCESS(权限不够)
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:14575次
排名:千里之外
原创:41篇
转载:11篇
(1)(4)(18)(16)(1)(12)新手园地& & & 硬件问题Linux系统管理Linux网络问题Linux环境编程Linux桌面系统国产LinuxBSD& & & BSD文档中心AIX& & & 新手入门& & & AIX文档中心& & & 资源下载& & & Power高级应用& & & IBM存储AS400Solaris& & & Solaris文档中心HP-UX& & & HP文档中心SCO UNIX& & & SCO文档中心互操作专区IRIXTru64 UNIXMac OS X门户网站运维集群和高可用服务器应用监控和防护虚拟化技术架构设计行业应用和管理服务器及硬件技术& & & 服务器资源下载云计算& & & 云计算文档中心& & & 云计算业界& & & 云计算资源下载存储备份& & & 存储文档中心& & & 存储业界& & & 存储资源下载& & & Symantec技术交流区安全技术网络技术& & & 网络技术文档中心C/C++& & & GUI编程& & & Functional编程内核源码& & & 内核问题移动开发& & & 移动开发技术资料ShellPerlJava& & & Java文档中心PHP& & & php文档中心Python& & & Python文档中心RubyCPU与编译器嵌入式开发驱动开发Web开发VoIP开发技术MySQL& & & MySQL文档中心SybaseOraclePostgreSQLDB2Informix数据仓库与数据挖掘NoSQL技术IT业界新闻与评论IT职业生涯& & & 猎头招聘IT图书与评论& & & CU技术图书大系& & & Linux书友会二手交易下载共享Linux文档专区IT培训与认证& & & 培训交流& & & 认证培训清茶斋投资理财运动地带快乐数码摄影& & & 摄影器材& & & 摄影比赛专区IT爱车族旅游天下站务交流版主会议室博客SNS站务交流区CU活动专区& & & Power活动专区& & & 拍卖交流区频道交流区
白手起家, 积分 22, 距离下一级还需 178 积分
论坛徽章:1
楼主小白,请教下各位前辈:
就我理解,linux下进程都有自己独立的地址空间等各项资源。在整个系统里就看上去是独立的执行程序,那么,这时候进程间通信时为何呢?
同时,由于各自独立的系统资源(地址空间),那么进程间通信怎么进行呢。
没有搞明白,麻烦各位指点一下。
&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp
稍有积蓄, 积分 236, 距离下一级还需 264 积分
论坛徽章:0
没有共享的,就在内核里面给他们搞一个共享的内存块咯。
然后进程访问的时候,从这个共享的地方复制到进程的私有空间去。
丰衣足食, 积分 677, 距离下一级还需 323 积分
论坛徽章:7
通过系统调用私通
家境小康, 积分 1257, 距离下一级还需 743 积分
论坛徽章:0
这种时候你要站的更高一些,不要把自己想象成一个普通的进程,而是要想象成一个操作系统。从安全易用的角度,你需要为你的用户(应用程序)设计一套完备的虚拟环境,这就是所谓的“独立”。而他们之间也有相互通讯的需求,所以,你还要考虑为他们设计一套通讯机制。这个不是能不能的问题,而是要不要的问题。有需求就必须要实现,仅此而已。)
北京皓辰网域网络信息技术有限公司. 版权所有 京ICP证:060528号 北京市公安局海淀分局网监中心备案编号:
广播电视节目制作经营许可证(京) 字第1234号
中国互联网协会会员&&联系我们:
感谢所有关心和支持过ChinaUnix的朋友们
转载本站内容请注明原作者名及出处2012年9月 Windows专区大版内专家分月排行榜第一2012年9月 C/C++大版内专家分月排行榜第一2012年8月 Windows专区大版内专家分月排行榜第一
2012年9月 其他开发语言大版内专家分月排行榜第二2012年8月 VC/MFC大版内专家分月排行榜第二2012年8月 其他开发语言大版内专家分月排行榜第二
本帖子已过去太久远了,不再提供回复功能。

我要回帖

更多关于 进程间通信 的文章

 

随机推荐