📄 ch13.htm
字号:
of <TT><FONT FACE="Courier">0</FONT></TT>, <TT><FONT FACE="Courier">-1</FONT></TT>,
<TT><FONT FACE="Courier">-2</FONT></TT>, and so on, depending
on how many processes are using it. A value of <TT><FONT FACE="Courier">0</FONT></TT>
indicates that the resource is unavailable. When a resource is
locked by a process, the value of the semaphore is decremented.
When the resource is freed, the value of the semaphore is incremented.
A semaphore value of less than <TT><FONT FACE="Courier">0</FONT></TT>
indicates that the process must block (that is, wait until some
other process zeroes it).
<P>
A semaphore is a data structure in the kernel that contains the
process ID of the last process to perform a semaphore operation
and the number of processes waiting on the semaphore to be <TT><FONT FACE="Courier">0</FONT></TT>.
A binary semaphore uses a value of either <TT><FONT FACE="Courier">1</FONT></TT>
or <TT><FONT FACE="Courier">0</FONT></TT>.
<P>
To use a semaphore, you must first create it. To do this, call
the <TT><FONT FACE="Courier">semget</FONT></TT> function. Here's
the syntax of the <TT><FONT FACE="Courier">semget</FONT></TT>
function:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">$semid = semget ($key, $num, $flag);</FONT></TT>
</BLOCKQUOTE>
<P>
The key and flag here are the same as those for shared memory
or message queues. 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 semaphore is created and its ID is returned in <TT><FONT FACE="Courier">semid</FONT></TT>.
The <TT><FONT FACE="Courier">$num</FONT></TT> variable is the
number of semaphores created and is an index into an array of
semaphores. The first element of the array is at index <TT><FONT FACE="Courier">0</FONT></TT>.
<P>
If <TT><FONT FACE="Courier">semget</FONT></TT> is unable to create
the semaphore, <TT><FONT FACE="Courier">$semid</FONT></TT> is
set to the null string.
<P>
To perform a semaphore operation, call the <TT><FONT FACE="Courier">semop()</FONT></TT>
function. Here's the syntax of the <TT><FONT FACE="Courier">semop()</FONT></TT>
function:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">semop ($semid, $semstructs);</FONT></TT>
</BLOCKQUOTE>
<P>
Here, <TT><FONT FACE="Courier">$semid</FONT></TT> is the semaphore
ID returned by <TT><FONT FACE="Courier">semget</FONT></TT>, and
<TT><FONT FACE="Courier">$semstructs</FONT></TT> is a character
string consisting of an array of semaphore structures.
<P>
Each semaphore structure consists of the following components,
each of which is a short integer (as created by the <TT><FONT FACE="Courier">s</FONT></TT>
format character in <TT><FONT FACE="Courier">pack</FONT></TT>):
<UL>
<LI><FONT COLOR=#000000>The number of semaphores</FONT>
<LI><FONT COLOR=#000000>The semaphore operation</FONT>
<LI><FONT COLOR=#000000>The semaphore flags, if any</FONT>
</UL>
<P>
This function returns a non-zero value if the semaphore operation
is successful; otherwise, <TT><FONT FACE="Courier">0</FONT></TT>
if an error occurs.
<P>
There are three actions you can take with a semaphore. Each of
these actions happens on the elements of the array you created
in the <TT><FONT FACE="Courier">semget()</FONT></TT> function.
These actions add or subtract a value to the semaphore:
<UL>
<LI><FONT COLOR=#000000>Adjust the value </FONT>by adding <TT><FONT FACE="Courier">0</FONT></TT>
to the semaphore. This action causes the resource controlled by
the semaphore to be acquired.
<LI><FONT COLOR=#000000>Increment the value of the semaphore.
This causes the resource to be marked as "released."
The calling process can now wait until the value is </FONT><TT><FONT FACE="Courier">0</FONT></TT>
again. Generally, you would increment by <TT><FONT FACE="Courier">1</FONT></TT>,
but you can use an arbitrary positive constant.
<LI><FONT COLOR=#000000>Decrement the value of the semaphore.
A decrement marks the use of a resource. This decrement may cause
the value of the semaphore to be less than </FONT><TT><FONT FACE="Courier">0</FONT></TT>.
If the value of the semaphore is less than <TT><FONT FACE="Courier">0</FONT></TT>,
the calling process will block until some other process that is
using or controlling the resource resets the value to <TT><FONT FACE="Courier">0</FONT></TT>.
</UL>
<P>
The <TT><FONT FACE="Courier">semctl</FONT></TT> function enables
you to set options for semaphores and issue commands that affect
them. Here's the syntax of the <TT><FONT FACE="Courier">semctl</FONT></TT>
function:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">$err = semctl ($semid, $semcmd, $semarg);</FONT></TT>
</BLOCKQUOTE>
<P>
<TT><FONT FACE="Courier">$semid</FONT></TT> is the semaphore ID
returned by <TT><FONT FACE="Courier">semget</FONT></TT>. <TT><FONT FACE="Courier">$semcmd</FONT></TT>
is the command that affects the semaphore; the list of available
commands includes the <TT><FONT FACE="Courier">Ipc_RMID</FONT></TT>
for removing the resource. Check the <TT><FONT FACE="Courier">ipc.ph</FONT></TT>
file for more commands on your system. Some of the commands that
can be specified by <TT><FONT FACE="Courier">semcmd</FONT></TT>
set the values of semaphore options. If one of these commands
is specified, the new value of the option is specified in <TT><FONT FACE="Courier">$semarg</FONT></TT>.
<P>
If an error occurs, <TT><FONT FACE="Courier">semctl</FONT></TT>
returns the undefined value; otherwise, it returns <TT><FONT FACE="Courier">0</FONT></TT>.
<P>
Listing 13.6 shows an example of a parent and child process sharing
a shared memory resource using semaphores.
<HR>
<BLOCKQUOTE>
<B>Listing 13.6. Using semaphores and shared memory together.
<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier"> 1 #!/usr/bin/perl<BR>
2 $|=1;<BR>
3 #<BR>
4 # Get the required files.<BR>
5 #<BR>
6 unshift (@Inc,"/usr/lib/perl5/i486-linux/5.002/sys");
<BR>
7 unshift (@Inc,"/usr/lib/perl5/i486-linux/5.002/linux");
<BR>
8 unshift (@Inc,"/usr/lib/perl5/i486-linux/5.002/asm");
<BR>
9 require "ipc.ph";
<BR>
10 require "shm.ph";<BR>
11 require "sem.ph";<BR>
12 #<BR>
13 # Identify yourself and the resource parameters.<BR>
14 #<BR>
15 $ppid = $$; #
for the parent<BR>
16 $ipckey = 34;<BR>
17 $PERMISSIONS=0666;<BR>
18 $semid = semget($ipckey,1,&Ipc_CREAT|$PERMISSIONS);<BR>
19 $semnum = 0;<BR>
20 $semflags = 0;<BR>
21 #<BR>
22 # Now create the shared memory segment. Note that we use the
same key.<BR>
23 #<BR>
24 $size = 1024;<BR>
25 $msgid = shmget($ipckey, $size, &Ipc_CREAT | $PERMISSIONS);
<BR>
26 # printf "\n Shared Memory Id = $msgid";<BR>
27 $pid = fork;<BR>
28 if ($pid == -1) {<BR>
29 die "\nFork failed. This is not
UNIX";<BR>
30 }<BR>
31 if ($pid) { # child process
<BR>
32 for ($i=0;$i<10;$i++) {<BR>
33 $semop = 0; #
Wait for resource<BR>
34 $semopstr = pack("sss",$semnum,$semop,$semflags);
<BR>
35 die "Cannot get semaphore"
unless semop($semid,$semopstr);<BR>
36 #<BR>
37 #<BR>
38 printf "\n Child: read from shared
memory ";<BR>
39 $retval = shmread($msgid, $message,
0, 80);<BR>
40<BR>
41 $semop = 2;<BR>
42 $semopstr = pack("sss",$semnum,$semop,$semflags);
<BR>
43 die "Cannot get semaphore"
unless semop($semid,$semopstr);<BR>
44 }<BR>
45 }<BR>
46 else { # in parent<BR>
47 for ($i=0;$i<10;$i++) {<BR>
48 $semop = -1;<BR>
49 $semopstr = pack("sss",$semnum,$semop,$semflags);
<BR>
50 die "Cannot get semaphore"
unless semop($semid,$semopstr);<BR>
51 printf "\n Parent: write to shared
memory";<BR>
52 shmwrite($msgid, $message, 0, 80);
<BR>
53<BR>
54 $semop = -1;<BR>
55 $semopstr = pack("sss",$semnum,$semop,$semflags);
<BR>
56 die "Cannot get semaphore"
unless semop($semid,$semopstr);<BR>
57 }<BR>
58 printf "\n In parent, removing
the semaphore";<BR>
59 semctl($semid,0,&Ipc_RMID,0);<BR>
60 printf "\n In parent, removing
the shared memory segment";<BR>
61 shmctl($msgid,&Ipc_RMID,0);<BR>
62 }</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
Line 2 specifies that the buffers be flushed immediately on write.
This is a good idea when you are working with forked processes.
<P>
Lines 5 through 11 set up the include paths for the required header
files. In lines 15 through 20 the semaphore is set up and created
for parent and child processes to use. In line 24 the shared memory
segment is created.
<P>
The process forks off into two processes in line 27. The child
process waits for the semaphore by first explicitly setting the
local counter to <TT><FONT FACE="Courier">0</FONT></TT> (see line
33). Then it checks for the value of the semaphore in line 35
after packing the parameters into the semaphore structure in line
34. When it breaks out of the semaphore (that is, when the value
of the semaphore is <TT><FONT FACE="Courier">0</FONT></TT>), the
child reads data from the shared memory segment. It then sets
the value of the semaphore to <TT><FONT FACE="Courier">2</FONT></TT>.
<P>
The parent, on the other hand, decrements the semaphore by <TT><FONT FACE="Courier">1</FONT></TT>.
The value is <TT><FONT FACE="Courier">2</FONT></TT> if the child
runs first, and thus becomes <TT><FONT FACE="Courier">1</FONT></TT>,
giving the parent control. If the child is running and adding
to shared memory, then the value of the semaphore is <TT><FONT FACE="Courier">0</FONT></TT>;
therefore, decrementing by the parent forces it to <TT><FONT FACE="Courier">-1</FONT></TT>,
thus blocking the parent. Now, when the child increments by <TT><FONT FACE="Courier">2</FONT></TT>,
the semaphore is set to <TT><FONT FACE="Courier">1 (-1 + 2 = 1)</FONT></TT>
and the parent is started. The child then waits until the semaphore
becomes <TT><FONT FACE="Courier">0</FONT></TT>, which happens
when the parent decrements the semaphore one more time.
<P>
The <TT><FONT FACE="Courier">shmctl</FONT></TT> and <TT><FONT FACE="Courier">semctl</FONT></TT>
functions are used to obliterate the Ipc resources once you are
done with the application.
<H2><A NAME="TheSysVIpcModule"><FONT SIZE=5 COLOR=#FF0000>The
</FONT><TT><FONT SIZE=5 COLOR=#FF0000 FACE="Courier">SysV::Ipc</FONT></TT><FONT SIZE=5 COLOR=#FF0000>
Module</FONT></A></H2>
<P>
The SysV Ipc code in Listing 13.6 was written long ago and has
been documented to death in almost all UNIX texts. Some kind folks
have tried to make the interface easier to use by providing modules
to make the interface cleaner. For the latest version of this
module, please check the CPAN sites listed in appendix B, "Perl
Module Archives."
<P>
It looks simple enough already, but it can always be tweaked a
little bit more. Check out the <TT><FONT FACE="Courier">Ipc::SysV</FONT></TT>
modules written by Jack Shirazi. Unfortunately, I could not get
this module to compile and work for Perl 5.002. There was not
any documentation or follow up address for me to get more information
about the module. You can try to get it to work on your system,
but with the application interface the way it is now, you should
ask yourself this question: Will the module make it simpler? If
the answer is yes, by all means go for it!
<H2><A NAME="ApplicationsofIpc"><FONT SIZE=5 COLOR=#FF0000>Applications
of Ipc</FONT></A></H2>
<P>
There are several ways that you can apply the Ipc tools you have
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -