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

📄 ch13.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
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">&amp;Ipc_PRIVATE</FONT></TT>

or the flag has <TT><FONT FACE="Courier">&amp;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 &quot;released.&quot;

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">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 $|=1;<BR>

&nbsp;3 #<BR>

&nbsp;4 #&nbsp;&nbsp;Get the required files.<BR>

&nbsp;5 #<BR>

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

<BR>

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

<BR>

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

<BR>

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

<BR>

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

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

12 #<BR>

13 # Identify yourself and the resource parameters.<BR>

14 #<BR>

15 $ppid = $$;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

for the parent<BR>

16 $ipckey = 34;<BR>

17 $PERMISSIONS=0666;<BR>

18 $semid = semget($ipckey,1,&amp;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, &amp;Ipc_CREAT | $PERMISSIONS);

<BR>

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

27 $pid = fork;<BR>

28 if ($pid == -1) {<BR>

29&nbsp;&nbsp;&nbsp;&nbsp; die &quot;\nFork failed. This is not

UNIX&quot;;<BR>

30 }<BR>

31 if ($pid)&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;# child process

<BR>

32&nbsp;&nbsp;&nbsp;&nbsp; for ($i=0;$i&lt;10;$i++) {<BR>

33&nbsp;&nbsp;&nbsp;&nbsp; $semop = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

Wait for resource<BR>

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

<BR>

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

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

36&nbsp;&nbsp;&nbsp;&nbsp; #<BR>

37&nbsp;&nbsp;&nbsp;&nbsp; #<BR>

38&nbsp;&nbsp;&nbsp;&nbsp; printf &quot;\n Child: read from shared

memory &quot;;<BR>

39&nbsp;&nbsp;&nbsp;&nbsp; $retval = shmread($msgid, $message,

0, 80);<BR>

40<BR>

41&nbsp;&nbsp;&nbsp;&nbsp; $semop = 2;<BR>

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

<BR>

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

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

44&nbsp;&nbsp;&nbsp;&nbsp; }<BR>

45 }<BR>

46 else { # in parent<BR>

47&nbsp;&nbsp;&nbsp;&nbsp; for ($i=0;$i&lt;10;$i++) {<BR>

48&nbsp;&nbsp;&nbsp;&nbsp; $semop = -1;<BR>

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

<BR>

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

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

51&nbsp;&nbsp;&nbsp;&nbsp; printf &quot;\n Parent: write to shared

memory&quot;;<BR>

52&nbsp;&nbsp;&nbsp;&nbsp; shmwrite($msgid, $message, 0, 80);

<BR>

53<BR>

54&nbsp;&nbsp;&nbsp;&nbsp; $semop = -1;<BR>

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

<BR>

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

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

57&nbsp;&nbsp;&nbsp;&nbsp; }<BR>

58&nbsp;&nbsp;&nbsp;&nbsp; printf &quot;\n In parent, removing

the semaphore&quot;;<BR>

59&nbsp;&nbsp;&nbsp;&nbsp; semctl($semid,0,&amp;Ipc_RMID,0);<BR>

60&nbsp;&nbsp;&nbsp;&nbsp; printf &quot;\n In parent, removing

the shared memory segment&quot;;<BR>

61&nbsp;&nbsp;&nbsp;&nbsp; shmctl($msgid,&amp;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, &quot;Perl

Module Archives.&quot;

<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 + -