📄 ch13.htm
字号:
<TT><FONT FACE="Courier">------ Shared Memory Segments --------
<BR>
shmid owner perms
bytes nattch status
<BR>
<BR>
------ Semaphore Arrays --------<BR>
semid owner perms
nsems status<BR>
<BR>
------ Message Queues --------<BR>
msqid owner perms
used-bytes messages<BR>
512 khusain 666
0
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, &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>
local($signalName) = @_;<BR>
</FONT></TT> <TT><FONT FACE="Courier">
print "\n Caught signal, removing message queue";<BR>
$ret= msgctl($msgid,&Ipc_RMID,$NULL)
;<BR>
</FONT></TT> <TT><FONT FACE="Courier">
print "\n System returned $ret from kill message queue";
<BR>
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">&Ipc_PRIVATE</FONT></TT>
or an arbitrary constant. If the key is <TT><FONT FACE="Courier">&Ipc_PRIVATE</FONT></TT>
or the flag has <TT><FONT FACE="Courier">&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"> 1 #!/usr/bin/perl<BR>
2 <BR>
3 unshift (@Inc,"/usr/lib/perl5/i486-linux/5.002/sys");
<BR>
4 unshift (@Inc,"/usr/lib/perl5/i486-linux/5.002/linux");
<BR>
5 unshift (@Inc,"/usr/lib/perl5/i486-linux/5.002/asm");
<BR>
6 <BR>
7 require "ipc.ph";
<BR>
8 require "shm.ph";<BR>
9 <BR>
10 $PERMISSIONS=0666;<BR>
11 $ipckey = 42;<BR>
12 $size = 1024;<BR>
13 <BR>
14 $msgid = shmget($ipckey, $size, &Ipc_CREAT | $PERMISSIONS);
<BR>
15 <BR>
16 printf "\n Shared Memory Id = $msgid";<BR>
17 <BR>
18 $message = "Segment #1";<BR>
19 print "\n Message = " . $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"> 1 #!/usr/bin/perl<BR>
2 <BR>
3 unshift (@Inc,"/usr/lib/perl5/i486-linux/5.002/sys");
<BR>
4 unshift (@Inc,"/usr/lib/perl5/i486-linux/5.002/linux");
<BR>
5 unshift (@Inc,"/usr/lib/perl5/i486-linux/5.002/asm");
<BR>
6 <BR>
7 require "ipc.ph";
<BR>
8 require "shm.ph";<BR>
9 <BR>
10 $PERMISSIONS=0666;<BR>
11 $ipckey = 42;<BR>
12 $size = 1024;<BR>
13 <BR>
14 $msgid = shmget($ipckey, $size, &Ipc_CREAT | $PERMISSIONS);
<BR>
15 <BR>
16 printf "\n Shared Memory Id = $msgid";<BR>
17 <BR>
18 $retval = shmread($msgid, $message, 0, 80);<BR>
19 <BR>
20 print "\n Read data:". $message. "ret value=
$retval" ;</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 + -