《Linux下C语言编程--进程通信pxz.docx》由会员分享,可在线阅读,更多相关《Linux下C语言编程--进程通信pxz.docx(18页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、Linuux下CC语言编编程-进程通通信、消消息管理理1、POOSIXX无名信信号量 如果果你学习习过操作作系统,那么肯肯定熟悉悉PV操操作了.PV操操作是原原子操作作.也就就是操作作是不可可以中断断的,在在一定的的时间内内,只能能够有一一个进程程的代码码在CPPU上面面执行.在系统统当中,有时候候为了顺顺利的使使用和保保护共享享资源,大家提提出了信信号的概概念. 假设我我们要使使用一台台打印机机,如果果在同一一时刻有有两个进进程在向向打印机机输出,那么最最终的结结果会是是什么呢呢.为了了处理这这种情况况,POOSIXX标准提提出了有有名信号号量和无无名信号号量的概概念,由由于Liinuxx只
2、实现现了无名名信号量量,我们们在这里里就只是是介绍无无名信号号量了. 信号号量的使使用主要要是用来来保护共共享资源源,使的的资源在在一个时时刻只有有一个进进程所拥拥有.为为此我们们可以使使用一个个信号灯灯.当信信号灯的的值为某某个值的的时候,就表明明此时资资源不可可以使用用.否则则就表示可以以使用. 为了了提供效效率,系系统提供供了下面面几个函函数 POSIIX的无无名信号号量的函函数有以以下几个个: #inccludde int semm_innit(semm_t *seem,iint pshhareed,uunsiigneed iint vallue); int semm_deestrro
3、y(semm_t *seem); int semm_waait(semm_t *seem); int semm_trrywaait(semm_t *seem); int semm_poost(semm_t *seem); int semm_geetvaaluee(seem_tt *ssem); sem_iniit创建建一个信信号灯,并初始始化其值值为vaaluee.pssharred决决定了信信号量能能否在几几个进程程间共享享.由于于目前LLinuux还没没有实现现进程间间共享信信号灯,所以这这个值只只能够取取0. semm_deestrroy是是用来删删除信号号灯的.semm_waait调调
4、用将阻阻塞进程程,直到到信号灯灯的值大大于0.这个函函数返回回的时候候自动的的将信号号灯的值值的件一一.seem_ppostt和seem_wwaitt相反,是将信信号灯的的内容加加一同时时发出信信号唤醒醒等待的的进程.seem_ttrywwaitt和seem_wwaitt相同,不过不不阻塞的的,当信信号灯的的值为00的时候候返回EEAGAAIN,表示以以后重试试.seem_ggetvvaluue得到到信号灯灯的值. 由于Liinuxx不支持持,我们们没有办办法用源源程序解解释了. 这几个函函数的使使用相当当简单的的.比如如我们有有一个程程序要向向一个系系统打印印机打印印两页.我们首首先创建建一
5、个信信号灯,并使其其初始值值为1,表示我我们有一一个资源源可用.然后一一个进程程调用ssem_waiit由于于这个时时候信号号灯的值值为1,所以这这个函数数返回,打印机机开始打打印了,同时信信号灯的的值为00 了. 如果果第二个个进程要要打印,调用ssem_waiit时候候,由于于信号灯灯的值为为0,资资源不可可用,于于是被阻阻塞了.当第一一个进程程打印完完成以后后,调用用semm_poost信信号灯的的值为11了,这这个时候候系统通通知第二二个进程程,于是是第二个个进程的的semm_waait返返回.第第二个进进程开始始打印了了. 不过我们们可以使使用线程程来解决决这个问问题的.我们会会在后
6、面面解释什什么是线线程的.编译包包含上面面这几个个函数的的程序要要加上 -lrrt选贤贤,以连连接liibrtt.soo库 2、Syysteem VV信号量量 为了了解决上上面哪个个问题,我们也也可以使使用Syysteem VV信号量量.很幸幸运的是是Linnux实实现了SSysttem V信号号量.这这样我们们就可以以用实例例来解释释了. Sysstemm V信信号量的的函数主主要有下下面几个个. #inccludde #inccludde #inccludde key_t fftokk(chhar *paathnnamee,chhar prooj); int semmgett(keey_t
7、t keey,iint nseems,intt seemfllg); int semmctll(innt ssemiid,iint semmnumm,innt ccmd,uniion semmun argg); int semmop(intt seemidd,sttrucct ssembbuf *sppos,intt nssposs); struuct semmbuff shorrt ssem_numm; /* 使使用那一一个信号号 */ shorrt ssem_op; /* 进行行什么操操作 */ shorrt ssem_flgg; /* 操操作的标标志 */ ; ftokk函数是是根据pp
8、athhnamme和pprojj来创建建一个关关键字.semmgett创建一一个信号号量.成成功时返返回信号号的IDD,keey是一一个关键键字,可可以是用用ftook创建建的也可可以是IIPC_PRIIVATTE表明明由系统统选用一一个关键键字. nseems表表明我们们创建的的信号个个数.ssemfflg是是创建的的权限标标志,和和我们创创建一个个文件的的标志相相同. semcctl对对信号量量进行一一系列的的控制.semmid是是要操作作的信号号标志,semmnumm是信号号的个数数,cmmd是操操作的命命令.经经常用的的两个值值是:SSETVVAL(设置信信号量的的值)和和IPCC_R
9、MMID(删除信信号灯).arrg是一一个给ccmd的的参数. semoop是对对信号进进行操作作的函数数.seemidd是信号号标志,spoos是一一个操作作数组表表明要进进行什么么操作,nsppos表表明数组组的个数数. 如如果seem_oop大于于0,那那么操作作将seem_oop加入入到信号号量的值值中,并并唤醒等等待信号号增加的的进程. 如果果为0,当信号号量的值值是0的的时候,函数返返回,否否则阻塞塞直到信信号量的的值为00. 如如果小于于0,函函数判断断信号量量的值加加上这个个负值.如果结结果为00唤醒等等待信号号量为00的进程程,如果果小与00函数阻阻塞.如如果大于于0,那那么
10、从信信号量里里面减去去这个值值并返回回. 下面我们们一以一一个实例例来说明明这几个个函数的的使用方方法.这这个程序序用标准准错误输输出来代代替我们们用的打打印机. #inccludde #inccludde #inccludde #inccludde #inccludde #inccludde #inccludde #inccludde #inccludde #inccludde #deffinee PEERMSS S_IRUUSR|S_IIWUSSR voidd innit_semmaphhoree_sttrucct(sstruuct semmbuff *ssem,intt seemnuum
11、, int semmop,intt seemfllg) /* 初初始话信信号灯结结构 */ sem-seem_nnum=semmnumm; sem-seem_oop=ssemoop; sem-seem_fflg=semmflgg; int dell_seemapphorre(iint semmid) /* 信信号灯并并不随程程序的结结束而被被删除,如果我我们没删删除的话话(将11改为00) 可以用iipcss命令查查看到信信号灯,用ippcrmm可以删删除信号号灯的 */ #if 1 retuurn semmctll(seemidd,0,IPCC_RMMID); #enddif int mai
12、in(iint arggc,ccharr *arggv) chaar bbuffferMAXX_CAANONN,*c; intt i,n; intt seemidd,seemopp_reet,sstattus; pidd_t chiildppid; strructt seembuuf ssemwwaitt,seemsiignaal; if(arrgc!=2)|(n=atooi(aargvv1)Prroceess=%d-Paarennt=%d-Chiild=%dn, i,geetpiid(),geetpppid(),cchilldpiid); c=buuffeer; /* 这这里要求求资源,进入
13、原原子操作作 */ whille(seemopp_reet=ssemoop(ssemiid,&semmwaiit,11)=-11)&(errrnoo=EEINTTR); if(ssemoop_rret=-11) fpriintff(sttderrr,%dd:DDecrremeent Semmaphhoree Errrorr:%ssna, ggetppid(),sstreerroor(eerrnno); elsee whille(*c!=00)ffputtc(*c+,sttderrr); /* 原原子操作作完成,赶快释释放资源源 */ whille(seemopp_reet=ssemoop(ss
14、emiid,&semmsiggnall,1)=-1)&(errrno=EIINTRR); if(ssemoop_rret=-11) ffpriintff(sttderrr,%dd:IIncrremeent Semmaphhoree Errrorr:%ssna, ggetppid(),sstreerroor(eerrnno); /* 不不能够在在其他进进程反问问信号灯灯的时候候,我们们删除了了信号灯灯 */ whille(waiit(&staatuss)=-1)&(errrno=EIINTRR); /* 信信号灯只只能够被被删除一一次的 */ if(ii=11) if(dell_seemapph
15、orre(ssemiid)=-11) fpprinntf(stdderrr,%d:Deestrroy Semmaphhoree Errrorr:%ssna, ggetppid(),sstreerroor(eerrnno); exitt(0); 信号灯的的主要用用途是保保护临界界资源(在一个个时刻只只被一个个进程所所拥有). 3、SyysteemV消消息队列列 为了了便于进进程之间间通信,我们可可以使用用管道通通信 SSysttemVV也提供供了一些些函数来来实现进进程的通通信.这这就是消消息队列列. #iinclludee #iinclludee #iinclludee innt mmsggg
16、et(keyy_t keyy,innt mmsgfflg); innt mmsgssnd(intt mssgidd,sttrucct mmsgbbuf *mssgp,intt mssgszz,innt mmsgfflg); innt mmsgrrcv(intt mssgidd,sttrucct mmsgbbuf *mssgp,intt mssgszz, longg mssgtyype,intt mssgfllg); innt mmsgcctl(Intt mssgidd,innt ccmd,strructt mssqidd_dss *bbuf); struuct msggbuff longg m
17、ssgtyype; /* 消息类类型 */ . /* 其他他数据类类型 */ msggget函函数和ssemgget一一样,返返回一个个消息队队列的标标志.mmsgcctl和和semmctll是对消消息进行行控制. mssgsnnd和mmsgrrcv函函数是用用来进行行消息通通讯的.msggid是是接受或或者发送送的消息息队列标标志. msggp是接接受或者者发送的的内容.msggsz是是消息的的大小. 结构构msggbuff包含的的内容是是至少有有一个为为msggtyppe.其其他的成成分是用用户定义义的.对对于发送送函数mmsgfflg指指出缓冲冲区用完完时候的的操作.接受函函数指出出无消
18、息息时候的的处理.一般为为0. 接收函函数mssgtyype指指出接收收消息时时候的操操作. 如果mssgtyype=0,接接收消息息队列的的第一个个消息.大于00接收队队列中消消息类型型等于这这个值的的第一个个消息.小于00接收消消息队列列中小于于或者等等于mssgtyype绝绝对值的的所有消消息中的的最小一一个消息息. 我我们以一一个实例例来解释释进程通通信.下下面这个个程序有有serrverr和clliennt组成成.先运运行服务务端后运运行客户户端. 服务端 serrverr.c #inccludde #inccludde #inccludde #inccludde #inccludd
19、e #inccludde #inccludde #inccludde #inccludde #deffinee MSGG_FIILE seerveer.cc #deffinee BUFFFERR 2555 #deffinee PERRM SS_IRRUSRR|S_IWUUSR struuct msggtyppe longg mttypee; charr buuffeerBBUFFFER+1; ; int maiin() sstruuct msggtyppe mmsg; kkey_t kkey; iint msggid; iif(keyy=fttok(MSGG_FIILE,a)=-11) fpr
20、iintff(sttderrr,Creeat Keyy Errrorr:%ssan,strrerrror(errrno); exitt(1); iff(mmsgiid=mmsggget(keyy,PEERM|IPCC_CRREATT|IPPC_EEXCLL)=-11) fpriintff(sttderrr,Creeat Messsagge Errror:%sann,sstreerroor(eerrnno); exitt(1); whhilee(1) msgrrcv(msggid,&mssg,ssizeeof(strructt mssgtyype),1,0); fpriintff(sttderr
21、r,Serrverr Reeceiive:%sn,msgg.buuffeer); msg.mtyype=2; msgssnd(msggid,&mssg,ssizeeof(strructt mssgtyype),0); exxit(0); - 客户端(cliientt.c) #inccludde #inccludde #inccludde #inccludde #inccludde #inccludde #inccludde #inccludde #deffinee MSGG_FIILE seerveer.cc #deffinee BUFFFERR 2555 #deffinee PERRM SS
22、_IRRUSRR|S_IWUUSR struuct msggtyppe longg mttypee; charr buuffeerBBUFFFER+1; ; int maiin(iint arggc,ccharr *arggv) sstruuct msggtyppe mmsg; kkey_t kkey; iint msggid; iif(aargcc!=22) fpriintff(sttderrr,Usaage:%s strringgna,arggv00); exitt(1); iif(keyy=fttok(MSGG_FIILE,a)=-11) fpriintff(sttderrr,Creea
23、t Keyy Errrorr:%ssan,strrerrror(errrno); exitt(1); iff(mmsgiid=mmsggget(keyy,PEERM)=-1) fpriintff(sttderrr,Creeat Messsagge Errror:%sann,sstreerroor(eerrnno); exitt(1); mssg.mmtyppe=11; sttrnccpy(msgg.buuffeer,aargvv1,BUUFFEER); mssgsnnd(mmsgiid,&msgg,siizeoof(sstruuct msggtyppe),0); meemseet(&msgg,
24、0,sizzeoff(sttrucct mmsgttypee); mssgrccv(mmsgiid,&msgg,siizeoof(sstruuct msggtyppe),2,00); fpprinntf(stdderrr,CClieent recceivve:%snn,mmsg.buffferr); exxit(0); 注意服务务端创建建的消息息队列最最后没有有删除,我们要要使用iipcrrm命令令来删除除的. 4、SyysteemV共共享内存存 还有有一个进进程通信信的方法法是使用用共享内内存.SSysttemVV提供了了以下几几个函数数以实现现共享内内存. #inccludde #incc
25、ludde #inccludde int shmmgett(keey_tt keey,iint sizze,iint shmmflgg); voidd *sshmaat(iint shmmid,connst voiid *shmmadddr,iint shmmflgg); int shmmdt(connst voiid *shmmadddr); int shmmctll(innt sshmiid,iint cmdd,sttrucct sshmiid_dds *buff); shmgget和和shmmctll没有什什么好解解释的.sizze是共共享内存存的大小小. sshmaat是用用来连接接共
26、享内内存的.shmmdt是是用来断断开共享享内存的的.不要要被共享享内存词词语吓倒倒,共享享内存其其实很容容易实现现和使用用的.sshmaaddrr,shhmfllg我们们只要用用0代替替就可以以了.在在使用一一个共享享内存之之前我们们调用sshmaat得到到共享内内存的开开始地址址,使用用结束以以后我们们使用sshmddt断开开这个内内存. #inccludde #inccludde #inccludde #inccludde #inccludde #inccludde #inccludde #inccludde #deffinee PEERM S_IIRUSSR|SS_IWWUSRR in
27、t maiin(iint arggc,ccharr *arggv) intt shhmidd; chaar *p_aaddrr,*cc_adddr; if(arggc!=2) fpriintff(sttderrr,Usaage:%snaa,aargvv0); exitt(1); if(shhmidd=shhmgeet(IIPC_PRIIVATTE,110244,PEERM)=-1) fpriintff(sttderrr,Creeatee Shharee Meemorry EErroor:%snna,sttrerrrorr(errrnoo); exitt(1); if(forrk() p_adddr=shmmat(shmmid,0,00); memsset(p_aaddrr,0,10224); strnncpyy(p_adddr,aargvv1,10024); exitt(0); elsse c_adddr=shmmat(shmmid,0,00); prinntf(Clliennt gget %s,c_adddr); exitt(0); 这个程序序是父进进程将参参数写入入到共享享内存,然后子子进程把把内容读读出来.最后我我们要使使用ippcrmm释放资资源的.先用iipcss找出IID然后后用ippcrmm shhm IID删除除.