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

📄 ch13.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<TT><FONT FACE="Courier">------ Shared Memory Segments --------

<BR>

shmid&nbsp;&nbsp;&nbsp;&nbsp; owner&nbsp;&nbsp;&nbsp;&nbsp; perms&nbsp;&nbsp;&nbsp;&nbsp;

bytes&nbsp;&nbsp;&nbsp;&nbsp; nattch&nbsp;&nbsp;&nbsp;&nbsp;status

<BR>

<BR>

------ Semaphore Arrays --------<BR>

semid&nbsp;&nbsp;&nbsp;&nbsp; owner&nbsp;&nbsp;&nbsp;&nbsp; perms&nbsp;&nbsp;&nbsp;&nbsp;

nsems&nbsp;&nbsp;&nbsp;&nbsp; status<BR>

<BR>

------ Message Queues --------<BR>

msqid&nbsp;&nbsp;&nbsp;&nbsp; owner&nbsp;&nbsp;&nbsp;&nbsp; perms&nbsp;&nbsp;&nbsp;&nbsp;

used-bytes&nbsp;&nbsp;messages<BR>

512&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; khusain&nbsp;&nbsp;&nbsp;666&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

0</FONT></TT>

</BLOCKQUOTE>

<P>

It's not a good idea to leave Ipc objects around in the system.

The <TT><FONT FACE="Courier">msgctl()</FONT></TT> function is

used to set options for message queues and send commands that

affect them. Generally, this function is used to delete message

queues. Here's the syntax of the <TT><FONT FACE="Courier">msgctl</FONT></TT>

function:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$err =msgctl ($msgid, $msgcmd, $msgarg);</FONT></TT>

</BLOCKQUOTE>

<P>

<TT><FONT FACE="Courier">$msgid</FONT></TT> is the message queue

ID. The argument <TT><FONT FACE="Courier">$msgcmd</FONT></TT>

is the command to be sent to the message queue. The list of available

commands is defined in the file <TT><FONT FACE="Courier">ipc.ph</FONT></TT>.

Some of the commands that can be specified by <TT><FONT FACE="Courier">msgcmd</FONT></TT>

set the values of message queue options. If one of these commands

is specified, the new value of the option is specified in <TT><FONT FACE="Courier">msgarg</FONT></TT>.

If an error occurs, <TT><FONT FACE="Courier">msgctl</FONT></TT>

returns the undefined value. <TT><FONT FACE="Courier">msgctl()</FONT></TT>

also can return <TT><FONT FACE="Courier">0</FONT></TT> or a non-zero

value and will set <TT><FONT FACE="Courier">errno</FONT></TT>

in <TT><FONT FACE="Courier">$!</FONT></TT>.

<P>

To delete a queue, use the following command:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$ret = msgctl($msgid, &amp;Ipc_RMID,

$NULL);</FONT></TT>

</BLOCKQUOTE>

<P>

The value of the returned parameter will be <TT><FONT FACE="Courier">-1</FONT></TT>

if there is an error; otherwise, the value is <TT><FONT FACE="Courier">0</FONT></TT>.

Sometimes the message queue can be deleted in a signal handler,

like this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">sub cleanup {<BR>

&nbsp;&nbsp;&nbsp;&nbsp; local($signalName) = @_;<BR>

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

print &quot;\n Caught signal, removing message queue&quot;;<BR>

&nbsp;&nbsp;&nbsp;&nbsp; $ret= msgctl($msgid,&amp;Ipc_RMID,$NULL)

;<BR>

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

print &quot;\n System returned $ret from kill message queue&quot;;

<BR>

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

}</FONT></TT>

</BLOCKQUOTE>

<H2><A NAME="SharedMemory"><FONT SIZE=5 COLOR=#FF0000>Shared Memory</FONT></A>

</H2>

<P>

Message queues are great for sending messages in a LIFO order.

The major problem with message queues is that they can overflow

if no one is there to receive the messages. 

<P>

Shared memory areas have to be explicitly created before you can

use them. To do this, call the <TT><FONT FACE="Courier">shmget</FONT></TT>

function with a key as you did with message queues. Here's the

syntax of the <TT><FONT FACE="Courier">shmget</FONT></TT> function:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$shmid = shmget (<I>key, msize, flag</I>);</FONT></TT>

</BLOCKQUOTE>

<P>

As with message queues, <TT><FONT FACE="Courier">$key</FONT></TT>

is either <TT><FONT FACE="Courier">&amp;Ipc_PRIVATE</FONT></TT>

or an arbitrary constant. If the key is <TT><FONT FACE="Courier">&amp;Ipc_PRIVATE</FONT></TT>

or the flag has <TT><FONT FACE="Courier">&amp;Ipc_CREAT</FONT></TT>

set, the shared memory segment is created, and its ID is returned

in <TT><FONT FACE="Courier">$shmid</FONT></TT>. The <TT><FONT FACE="Courier">msize</FONT></TT>

is the size of the created shared memory in bytes. If <TT><FONT FACE="Courier">shmget()</FONT></TT>

cannot create the shared memory area, the returned value in  <TT><FONT FACE="Courier">$shmid</FONT></TT>

is set to <TT><FONT FACE="Courier">undef</FONT></TT>. The <TT><FONT FACE="Courier">$flags</FONT></TT>

are the same as with message queues.

<P>

Here are the actions you can perform on a shared memory segment:

<UL>

<LI><FONT COLOR=#000000>Write to it with the </FONT><TT><FONT FACE="Courier">shmwrite()</FONT></TT>

function

<LI><FONT COLOR=#000000>Read from it with the </FONT><TT><FONT FACE="Courier">shmread()</FONT></TT>

function

<LI><FONT COLOR=#000000>Delete or modify its parameters with the

</FONT><TT><FONT FACE="Courier">shmctl()</FONT></TT> function

</UL>

<H3><A NAME="TheshmwriteandshmreadFunctions">The <TT><FONT SIZE=4 FACE="Courier">shmwrite()</FONT></TT><FONT SIZE=4>

and </FONT><TT><FONT SIZE=4 FACE="Courier">shmread()</FONT></TT><FONT SIZE=4>

Functions</FONT></A></H3>

<P>

To write data to an area of shared memory, call the <TT><FONT FACE="Courier">shmwrite()</FONT></TT>

function. Here's the syntax of the <TT><FONT FACE="Courier">shmwrite</FONT></TT>

function:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">shmwrite ($shmid, $text, $pos, $size);</FONT></TT>

</BLOCKQUOTE>

<P>

<TT><FONT FACE="Courier">$shmid</FONT></TT> is the shared memory

ID returned by <TT><FONT FACE="Courier">shmget</FONT></TT>. <TT><FONT FACE="Courier">$text</FONT></TT>

is the character string to write to the shared memory, <TT><FONT FACE="Courier">$pos</FONT></TT>

is the number of bytes to skip over in the shared memory before

writing to it, and <TT><FONT FACE="Courier">$size</FONT></TT>

is the number of bytes to write.

<P>

This function returns a value that is the number of bytes actually

written or, in the case of an error, a value of <TT><FONT FACE="Courier">0</FONT></TT>.

<P>

If the data specified by <TT><FONT FACE="Courier">$text</FONT></TT>

is longer than the value specified by size, only the first <TT><FONT FACE="Courier">$size</FONT></TT>

bytes of text are written to the shared memory. If the data specified

by <TT><FONT FACE="Courier">$text</FONT></TT> is shorter than

the value specified by <TT><FONT FACE="Courier">$size</FONT></TT>,

<TT><FONT FACE="Courier">shmwrite</FONT></TT> generally will fill

the leftover space with null characters. An error also occurs

if you attempt to write too many bytes to the shared memory area

(that is, if the value of <TT><FONT FACE="Courier">$pos</FONT></TT>

plus <TT><FONT FACE="Courier">$size</FONT></TT> is greater than

the number of bytes in the shared memory segment).

<P>

To read data from a segment of shared memory, call the <TT><FONT FACE="Courier">shmread</FONT></TT>

function. Here's the syntax of the <TT><FONT FACE="Courier">shmread</FONT></TT>

function:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">shmread ($shmid, $retval, $pos, $size);</FONT></TT>

</BLOCKQUOTE>

<P>

Here, <TT><FONT FACE="Courier">$shmid</FONT></TT> is the shared

memory ID returned by <TT><FONT FACE="Courier">shmget</FONT></TT>.

The <TT><FONT FACE="Courier">$retval</FONT></TT> variable is a

scalar variable (or array element) in which the returned data

is to be stored. The data is read from <TT><FONT FACE="Courier">$pos</FONT></TT>

number of bytes from the start of the shared memory segment, and

<TT><FONT FACE="Courier">$size</FONT></TT> is the number of bytes

to copy. This function returns a non-zero value if the read operation

succeeds, or it returns <TT><FONT FACE="Courier">0</FONT></TT>

in the case of an error.

<P>

Only the number of bytes requested are returned in <TT><FONT FACE="Courier">$retval</FONT></TT>.

An error occurs if you attempt to read too many bytes from the

shared memory area. In other words, if the value of <TT><FONT FACE="Courier">$pos</FONT></TT>

plus <TT><FONT FACE="Courier">$size</FONT></TT> is greater than

the number of bytes in the shared memory segment, you'll get an

error. On errors, the values in the <TT><FONT FACE="Courier">$retval</FONT></TT>

scalar are undefined.

<P>

See Listing 13.4 for a simple Perl script that creates a memory

segment and then puts some data in it.

<HR>

<BLOCKQUOTE>

<B>Listing 13.4. The use of </B><TT><B><FONT FACE="Courier">shmget()</FONT></B></TT><B>

and </B><TT><B><FONT FACE="Courier">shmwrite()</FONT></B></TT><B>.

<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

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

&nbsp;2 <BR>

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

<BR>

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

<BR>

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

<BR>

&nbsp;6 <BR>

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

<BR>

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

&nbsp;9 <BR>

10 $PERMISSIONS=0666;<BR>

11 $ipckey = 42;<BR>

12 $size = 1024;<BR>

13 <BR>

14 $msgid = shmget($ipckey, $size, &amp;Ipc_CREAT | $PERMISSIONS);

<BR>

15 <BR>

16 printf &quot;\n Shared Memory Id = $msgid&quot;;<BR>

17 <BR>

18 $message = &quot;Segment #1&quot;;<BR>

19 print &quot;\n Message = &quot; . $message;<BR>

20 <BR>

21 shmwrite($msgid, $message, 0, 80);</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

Note that in Listing 13.5, the shared memory segment is 1,024

bytes long. The shared memory segment is not automatically destroyed

when the creating process is killed. The values and space for

these values in the shared memory area remain there even after

the process that created the segment is long gone.

<P>

A second application can now come in and read from the shared

memory segment. This second application is shown in Listing 13.5.

<HR>

<BLOCKQUOTE>

<B>Listing 13.5. The use of </B><TT><B><FONT FACE="Courier">shmread()</FONT></B></TT><B>.

<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

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

&nbsp;2 <BR>

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

<BR>

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

<BR>

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

<BR>

&nbsp;6 <BR>

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

<BR>

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

&nbsp;9 <BR>

10 $PERMISSIONS=0666;<BR>

11 $ipckey = 42;<BR>

12 $size = 1024;<BR>

13 <BR>

14 $msgid = shmget($ipckey, $size, &amp;Ipc_CREAT | $PERMISSIONS);

<BR>

15 <BR>

16 printf &quot;\n Shared Memory Id = $msgid&quot;;<BR>

17 <BR>

18 $retval = shmread($msgid, $message, 0, 80);<BR>

19 <BR>

20 print &quot;\n Read data:&quot;. $message. &quot;ret value=

$retval&quot; ;</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

This little example brings up a very possible and potentially

dangerous scenario concerning the use of shared memory to pass

data between two applications. Take two processes, A and B, which

share data through shared memory. What if process A is in the

middle of writing some data that B is reading? There is a high

probability that the data read by B could be mangled by A. There

is nothing that prevents B from reading from the same offset to

which A is writing.

<P>

To prevent such potentially erroneous read/write situations, you

have to lock the resource from multiple use. This is where semaphores

come into play. A semaphore allows multiple processes to synchronize

access on a resource.

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

</H2>

<P>

A semaphore is simply a counter in the kernel. It can have values

⌨️ 快捷键说明

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