⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch13.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
available. Generally, shared memory and semaphores have to be

used together. When working with large blocks of data, use shared

memory to pass the data between two processes. Synchronize the

transfer between processes via the use of a semaphore.

<P>

What if you have a situation in which more than one process is

required to process the data? Semaphores can get clunky at this

stage if you are not careful.

<P>

In a typical scenario, you could have one process collect data

from external devices and then have the data available in shared

memory for all other processes. The shared memory area will be

divided into partitions. Each partition is used only by one process

and only written to by the data collector. The data collector

updates all the sections of shared memory and then updates a semaphore

with the number of processes that are currently waiting to work

with this data. Then it sends a message to each of the processes

via a message queue. After sending all the messages, the data

collector process waits for the semaphore to be <TT><FONT FACE="Courier">0</FONT></TT>

again, thereby getting the signal to proceed.

<P>

Each data-handling process (client) can wait for messages forever

on its message queue. As soon as it receives a message on its

queue, the client can guarantee that it will have exclusive access

to its partition. After it has processed the data, the client

can decrement the semaphore. As each client increments the semaphore,

it will go back to the top of the loop and wait on the input message

queue again.

<P>

Once all the clients have incremented the semaphore, it becomes

<TT><FONT FACE="Courier">0</FONT></TT> again. This causes the

data collector to wake up and begin the process of collecting

and updating the shared memory area.

<P>

Listings 13.7 and 13.8 show a partial application for such a system.

These listings are by no means complete because this would require

a full-blown application well beyond the scope of this chapter.

The gist of the program is to illustrate how all three types of

Ipc objects can be used with each other to create relatively complex

applications.

<P>

The server application decrements the semaphore to block (while

the clients do what they have to do) and then increments the value

of the semaphore. The processes here have to run concurrently

in the background. There are three clients for the one server.

Obviously, this example is contrived for the book-you might have

more clients to handle your tasks.

<HR>

<BLOCKQUOTE>

<B>Listing 13.7. The server of a dummy application.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 unshift (@Inc,&quot;/usr/lib/perl5/i486-linux/5.002/sys&quot;);

<BR>

&nbsp;3 unshift (@Inc,&quot;/usr/lib/perl5/i486-linux/5.002/linux&quot;);

<BR>

&nbsp;4 unshift (@Inc,&quot;/usr/lib/perl5/i486-linux/5.002/asm&quot;);

<BR>

&nbsp;5 require &quot;ipc.ph&quot;;

<BR>

&nbsp;6 require &quot;shm.ph&quot;;<BR>

&nbsp;7 $PERMISSIONS=0666;

<BR>

&nbsp;8 $ipckey = 42;<BR>

&nbsp;9 $size = 4096;<BR>

10 #<BR>

11 # Create the shared memory segment<BR>

12 #<BR>

13 $| = 1;<BR>

14 @messages =&nbsp;&nbsp;(<BR>

15&nbsp;&nbsp;&nbsp;&nbsp; &quot;Process 0 &quot;,<BR>

16&nbsp;&nbsp;&nbsp;&nbsp; 'Process 1 ',<BR>

17&nbsp;&nbsp;&nbsp;&nbsp; 'Process 2 ',<BR>

18 );<BR>

19 $shmid = shmget($ipckey, $size, &amp;Ipc_CREAT | $PERMISSIONS);

<BR>

20 $count = $#messages + 1;<BR>

21 $semid = semget($ipckey,$count,&amp;Ipc_CREAT|$PERMISSIONS);

<BR>

22 $semflags = 0;<BR>

23 for ($offset = 0; $offset &lt; $count; $offset++) {<BR>

24&nbsp;&nbsp;&nbsp;&nbsp; $msg = $messages[$offset];<BR>

25&nbsp;&nbsp;&nbsp;&nbsp; $msgid[$offset] = msgget($ipckey <BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">$offset,&amp;Ipc_CREAT

| $PERMISSIONS);<BR>

26&nbsp;&nbsp;&nbsp;&nbsp; print &quot;\n Server: Creating Message

Queue: &quot;<BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">.

$msgid[$offset] . &quot;\n&quot;;<BR>

27&nbsp;&nbsp;&nbsp;&nbsp; }<BR>

28 printf &quot;\n Shared Memory Created Id = $shmid&quot;;<BR>

29 while(1)<BR>

30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>

31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$semop = $count;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

Stop the clients<BR>

32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$semopstr = pack(&quot;sss&quot;,$semnum,$semop,$semflags);

<BR>

33&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;die &quot;Cannot get semaphore&quot;

unless semop($semid,$semopstr);<BR>

34<BR>

35&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for ($offset = 0; $offset

&lt; $count; $offset++) {<BR>

36&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

$semnum = $offset;<BR>

37&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

$msg = $messages[$offset];<BR>

38&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

print &quot;\n Server: Writing &quot; . $msg . <BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">&quot;

at &quot; . $offset * 40 . &quot;\n&quot;;<BR>

39&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

shmwrite($shmid, $msg, $offset * 40, 12);<BR>

40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

$msg = pack(&quot;L a*&quot;, $offset + 1, &quot; Go for it!&quot;);

<BR>

41&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

print &quot;\n Server: Sending to&quot; . $msgid[$offset] . &quot;\n&quot;;

<BR>

42&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

msgsnd($msgid[$offset], &quot;$msg&quot;, &amp;Ipc_NOWAIT);<BR>

43&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

44&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$semop = -$count;&nbsp;&nbsp;&nbsp;&nbsp;

# Block till semaphore is 0<BR>

45&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$semopstr = pack(&quot;sss&quot;,$semnum,$semop,$semflags);

<BR>

46&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;die &quot;Cannot get semaphore

to wait&quot; unless semop($semid,$semopstr);<BR>

47&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(10);<BR>

48 }</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

Listing 13.8 is the client application to pick up the messages

from the server. The messages sent can contain additional information

for the client; that is, they don't have to be just triggers for

the client to proceed with reading. The contents of the messages

can contain information about how and where to pick up data from

shared memory.

<HR>

<BLOCKQUOTE>

<B>Listing 13.8. The client of a dummy application.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 #<BR>

&nbsp;3 # Usage =&nbsp;&nbsp;client

-p ProcessIndex<BR>

&nbsp;4 #<BR>

&nbsp;5 unshift (@Inc,&quot;/usr/lib/perl5/i486-linux/5.002/sys&quot;);

<BR>

&nbsp;6 unshift (@Inc,&quot;/usr/lib/perl5/i486-linux/5.002/linux&quot;);

<BR>

&nbsp;7 unshift (@Inc,&quot;/usr/lib/perl5/i486-linux/5.002/asm&quot;);

<BR>

&nbsp;8 use Getopt::Long;<BR>

&nbsp;9 $result = GetOptions

('p=i');<BR>

10 $| = 1;<BR>

11 if (($opt_p &lt; 0) || ($opt_p &gt; 3)) {<BR>

12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;die &quot;Usage: $0 -p ProcessIndex&quot;;

<BR>

13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(0);<BR>

14 }<BR>

15 require &quot;ipc.ph&quot;;<BR>

16 require &quot;shm.ph&quot;;<BR>

17 require &quot;msg.ph&quot;;<BR>

18 require &quot;sem.ph&quot;;<BR>

19 $PERMISSIONS=0666;<BR>

20 $msg_type = 0;<BR>

21 $msg_offset = $opt_p * 40;<BR>

22 $ipckey = 42;<BR>

23 $msg_key = $ipckey +&nbsp;&nbsp;$opt_p;<BR>

24 $size = 0;<BR>

25 $shmid = shmget($ipckey, $size, &amp;Ipc_CREAT | $PERMISSIONS);

<BR>

26 printf &quot;\n $$ = Shared Memory Id = $shmid&quot;;<BR>

27 $msgid = msgget($msg_key,&amp;Ipc_CREAT | $PERMISSIONS);<BR>

28 printf &quot;\n $$ =&nbsp;&nbsp;Message Id <BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">=

$msgid, Will read from $msg_offset, $msg_type\n&quot;;<BR>

29 $semid = semget($ipckey,3,&amp;Ipc_CREAT|$PERMISSIONS);<BR>

30 $semnum = 0;<BR>

31 $semflags = 0;<BR>

32 while (1)<BR>

33&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>

34&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print &quot;\n Read message

of type :&quot;. $msg_type;<BR>

35&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;msgrcv($msgid, $msg, 80,

$msg_type, 0);<BR>

36&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$retval = shmread($msgid,

$message, 0, 80);<BR>

37&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print &quot;\n Read message:&quot;.

$message. &quot;ret value= $retval&quot; ;<BR>

38&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$semop = 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

Clear yourself for server<BR>

39&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$semopstr = pack(&quot;sss&quot;,$semnum,$semop,$semflags);

<BR>

40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;die &quot;Cannot get semaphore&quot;

unless semop($semid,$semopstr);<BR>

41&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print &quot;\n After semaphore&quot;;

<BR>

42&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

The sample programs shown in Listings 13.7 and 13.8 provided the

basis for a prototype of a seismic data collection system. The

actual system was written in C for efficiency because of some

pretty lengthy mathematical calculations. However, with Perl,

we were able to use this code to get a proof-of-concept working

model up and running in just one afternoon. The prototype provided

us with enough information to consider using the Ipc model for

the application. In later models of the same application, I was

able to extend the processing to remote machines by replacing

the message queues with sockets and sending the requisite portions

of data along the sockets.

<P>

The final application was tested further by adding new Perl scripts

that share messages and simulate data using shared memory. Listings

13.7 and 13.8 are very similar to the working application and

have been created from scratch. It should be relatively painless

for you to take this code and extend it into your own prototype.

<H2><A NAME="Summary"><FONT SIZE=5 COLOR=#FF0000>Summary</FONT></A>

</H2>

<P>

Perl is a very powerful tool for prototyping applications. With

the capability to access the system facilities, Perl can provide

the necessary tools for rapid prototyping. Hopefully, this chapter

has provided you with enough information to set up your own applications.

<P>

This chapter has introduced you to the System V Ipc facilities

available through Perl. The Ipc objects are global and remain

in memory long after the processes that created them are gone.

With Ipc objects, you are limited to one machine. If your application

requires network access, consider using sockets instead.

<P>

Using message queues, you can send messages between processes.

For large data items, message queues might not be very efficient.

Consider using shared memory instead. To synchronize the access

to the shared memory, you can use semaphores to prevent one process

from writing to an area where another process might be reading.

<P>

<HR WIDTH="100%"></P>



<CENTER><P><A HREF="ch12.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/ch12.htm"><IMG SRC="pc.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/pc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="#CONTENTS"><IMG SRC="cc.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/cc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="index.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/index.htm"><IMG SRC="hb.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/hb.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="ch14.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/ch14.htm"><IMG 

SRC="nc.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/nc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A></P></CENTER>



<P>

<HR WIDTH="100%"></P>



</BODY>

</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -