东南大学硕士学位论文
前面也提到,由于pajnⅡ没有MMu内存管理单元,故在实现多个进程时(fofk调用生成子 进程)需要实现数据保护。由于pc【jnⅡ的多进程管理是通过vfork来实现.因此fork等于vfork。 这意味着pCIjnux系统fork调用完成后,要么子进程代替父进程执行(此时父进程已经sIe印)直到 子进程调用e疵退出:要么调用exec执行一个新的进程,这个时候将产生可执行文件的加载,即使 这个进程只是父进程的拷贝,这个过程也不能避免。当子进程执行e妣或excc后.子进程使用wakel】p 把父进程唤醒,使父进程继续往下执行。这就意味着父进程和子进程或者子进程和子进程不能同时
运行,显然不能符合这里要求。
所以,这里我们设计了两个并行的进程,从系统上来看即是两个程序。分别叫做通讯进程和 sRAM进程。这里就涉及到两个进程之间的通信问题,因为从上面的任务中也可以看出来,两个进 程都涉及到同个nash的操作(可以看成是普通文件流),一个是写,一个是读。我们知道,n勰h或者 普通文件流是不能同时进行读和写的操作,故这里就需要通过进程间通讯来达到两个进程问的同步。
5.3.2软件进程间通信的分析
所谓进程问通讯(Ⅱ,c)就是指多个进程之间相互通信,交换信息的方法。常见的进程间通信的 方法有以下几种:共享内存,信号量。管道,命名管道,消息队列等,这些都只适合于本地进程通 信。还有可用于远程通信的如套接口在网络编程中将涉及。
共享内存是系统中最底层的通信机制。也是最快速的通信机制。顾名思意,共享内存就是通过 两个或多个进程共享同一块内存区域来实现相互问通信,通常是由一个进程创建一块共享内存区域, 然后多个进程可以对其进行访问。虽然这种通信方式是最高效的进程问通信方式,但实际的问题在 于它本身就存在同步的问题,即不同进程同时读写一块共享内存中的数据时会发生混乱。针对这个 问题,一般是通过使用信号量来配合使用来实现进程间的同步。
信号量的实质是整数计数器,记录了可访问的共享资源的单元个数。当然。信号量并不仅仅用 于互斥共享内存的同步操作.它可实现对任意资源的锁定机制,即可以用来同步对任何共享资源的 访问。信号量中常见的形式是双态信号量,用于只有一个可供访问单元的互斥共享资源,保证任一 时刻至多只允许一个进程对资源进行访问。从上面的叙述可以看出j信号量本身只是一种实现进程 同步的机制,而无法进行包含有具体信息的通信,所以光用信号量无法满足本设计的要求。当然, 上面也提到,一般是用共享内存和信号量配合使用来到进程通信及同步的目的,在本课题的进行中, 也进行了相关的实验。虽然在功能上基本能达到要求,但首先同时使用共享内存和信号量,程序显 得烦琐,其次与后面要介绍的管道通信比,在满足本设计的要求方面,不如后者的简单方便。
管道(p虹≈).在Ij¨x中是作为一种特殊文件存在于内存中的,它的一个显著特点就是:当一 个管道建立后,将获得两个文件描述符,分别用于对管道的读取和写入,即通常称为的管道写入端 和读取端,而对一个进程来说,管道的写入与读取操作和对一个普通文件的读写操作相比没有区别, 只是内核中用这种机制来实现进程间的通信而已。和前面介绍的共享内存相比,管道机制通信速度 上要慢一些,但是使用上管道要方便的多。但是管道也存在其固有的局限性,首先管道只能用于两 个进程间的通信,而不能用于多进程间的通信。其次,通信的两个进程要有同源性,同源即他们必 须是由同个进程派生出来的进程,此外,管道是半双工方式的,只允许单方向传输数据。对于最后 一点,我们可以建立两个管道,一收一发,用两个半双工的来实现数据的双向传输。但是对于第二 点,在前面进程的分析中可知,本设计中,两个进程不能是同源的,只能是两个独立的进程,所以. 管道无法满足本设计的要求。
在使用上一样方便,即一旦创建,就可以像普通文件一样进行读写操作,此外,命名管道也只能用 于两个进程的通信,而且也是单向数据传输,所以要用命名管道实现两个进程问数据的相互交换, 需要使用两条命名管道。那么。命名管道与管道相比,其特殊体现在哪儿昵?首先,命名管道可以 用于任何两个进程间的通信,而不限制这两个进程是否同源,所以命名管道的使用要灵活的多,这 也符合本课题中的设计要求。其次,命名管道作为一种特殊的文件存在文件系统中的,而不是像管
32
即jo)是一种特殊的管道,又称为先进先出队列,它与管道 我们看一下命名管道,命名管道(
第五章uc“呲在Ⅱ'D异步卡中的应用 道一样存在内核。当进程对命
名管道的使用结束后,命名管道依然存在与文件系统中,所以在使用 时要注意,当不需要命名管道时,要记得对其进行删除操作.否则该命名管道不会消失。
同时要注意命名管道的阻塞问题,在实际调试过程过也遇到过。阻塞可能发生在两个地方,首 先是在通讯进程在初始化时建立创建了两个命名管道,然后用只读和只写方式分别打开,在用只读 方式先打开l号命名管道后,进程并不立即执行打开2号命名管道的操作,而是阻塞在这里等待 sRAM进程用相反方式(只写)打开1号进程,如果sRAM进程在初始化时先用只读方式打开通讯 进程创建的2号命名管道,那么进程也会阻塞在此等待通讯进程用只写方式打开2号进程,这样两 个进程就形成了死锁.都无法继续执行。当然避免这个死锁的方法也很简单,即sRAM进程先打开
1号进程就行了。也就是说,~个命名管道(普通管道也是一样)只有在写端和读端读打开过后才 算真正建立起来。其次在命名管道的读端读信息时,如果写端并没有写入信息,或则信息已经在读 端已经被读走了。这时读端的进程就会阻塞在次。这也就是说写端写入的信息在读过一次后就消失 了。并不永久保存在管道中,如果管道中没有信息,读端的操作可能会阻塞。这个问题可以从两个
NoNBLOCK标志,这样在管道没有 方面着手解决,一是在用open函数打开只读管道时,设置0L信息时,读操作也不会阻塞,而是立即返回。二是。在写端不要求通讯时,关闭(c10se)该管道, 这时读端也会因为没有信息可读而立即返回.当然读操作(read)返回的读出信息量为0:本设计才 用了后面的解决方法。
5.3.3软件进程间通信的具体协议
两个进程(通讯进程和sRAM进程)间的通信协议具体如下:先说通讯进程,在初始化时,先 建立两个命名管道.然后以只读和只写方式打开,发送并接收完测试信息后,关闭只写管道,这样, 每次sRAM进程端读出。个信息;然后在有网络连接时,通讯进程先打开只写管道并写入sToP信 息,然后等待sRAM进程回应oK信息,接着读网络数据保存。结束后在写管道中写入oK并继续 关闭该管道,这样一次通信完成:而在SRAM进程一端,在初始化时用相反的方式打开两个管道(即 SRAM进程里的只读管道是通讯进程的只写管道.SRAM进程里的只写管道是通讯进程的只读管 道),接着发送并接收完测试信息,然后循环从只读管道中读取数据,如果读出的信息量为O,则从 通讯进程保存的数据文件中读取数据写入sRAM中;如果管道有信息,则先看是否为s1DP,如是 则回应oK,并循环读管道直到读出oK为止,否则继续上述逻辑,这样也就完成了一次通信:
5.3.4软件流程图
综合上述,本设计中将建立两个独立的进程(通讯进程和SRAM进程),来完成接收数据和把 数据写入sRAM的任务,两个进程通过命名管道来是实现两个进程间的通信及同步,整个应用软件 的示意图如下:
通讯进程 1.建立命名管道 2.接收数据 3.保存数据
删进程
1.打开命名管道
.进程间通信7
2.读数据写入sRAM 3.与CPLD通信
图5_3软件示意图
通讯进程框图如下:
东南大学硕士学位论文
建立两个命名管道(只 读,只写)。并用只读和 只写方式分别打开
J』L
发送管道测试信息; 关闭只写管道
U 一初
始化网络。注意这 里设置为服务器端
图5.4通讯进程流程图
写sRAM进程框图如下:
第五章ucLi删x在uD异步卡中的应用
图5.5写SRAM进程流程图
5.4主要功能块的软件实现
5.4
.1进程通信的实现
1.首先看一下通讯进程的建立命名管道和测试信息的接收和发送:
if((mIdifo(册1,FⅡE MODE)《0)&&(efmo!=EE)(IsD) if((eⅡ幽卿2rr
sys(’乜m,FtcⅡEreaMtoeD%sE)《0。,F)&&徊_Ⅲ01); rⅡo!;嘲ST)){
Ⅷ】ink毋Ⅲ01);
err』”(”c锄tcmtc%s”,FⅡ;;02);
l’
35
东南大学硕士学位论文
rweraidtfedf=do=pocpn∞(唧l,O册2J'DOO、张oNI墨0I);//只读方式打开管道f叮LEifol
0);/,只写方式打开管道石f02 砌Lc№nt(0);,,向只写管道中写入信息”OK” waiLcli∞tO;,,等
待从只读管道中读出回应信息 close(writefd)://关闭只写管道 与之对应的sRAM进程对管道的初始化: Writefd=open(FIF0l,o_WRONLY,0)://只写方式打开管道丘fol
readfd=open(FIF02,o_RDONLY'0)://只读方式打开管道fi尬
tell server(0):,,向只写管道中写入信息”OK” Wait server():/,等待从只读管道中读出回应信息
2.两个进程间通信的实现。先看通讯进程一端: Writefd=open(FIF02,0_WRONLY,0)://只写方式打开管道丘fol tell—client
(1)://向只写管道中写入信息”SToP竹
%it_client()://等待从只读管道中读出回应信息
if(strncmp(buff,response[0】,2)!=o)
{ //如果不是正确的回应信息则进行错误处理 }
else//收到正确的回应信息 (
.
//从网络接收数据并写到数据文件中
tell.client(0)://向只写管道中写入信息”OK”
J close("itefd)://关闭只写管道 与之对应的sR枷进程的通信实现: While(1)//大循环
{
memset(buff,0,姒】(LI旧://清信息缓存区
clienti=Wait-server()://从只读管道中读出信息 if(clienti一0)//如果没有信息 f?//从数据文件中读出数据写入SRAII中
}
else if(clienti>0)//如果有信息
{
While(strncmp(buff,response[0],2)I_O)//判断是否为oK
{ if(st丌IcⅢp(buff,response[1],4)一O)//判断是否为STtell一server(O)://向只写管道中写入信息”OF
m∞set(buff。0,姒)[LINE):////清信息缓存区 Wait—se玎,er()://继续从只读管道读信息
} ) }
5.4 .2网络通信的实现 1.先看初始化:
if((sock“一listen=socket(AF_INET,SOCK_STRE_^lI,O))<o)//建立套接字
{ err_quit(’failed tD creat listen socket\n’): ) socket-addr.sin-f∞ily=AF-IN盱:
36
oP信息