📄 perlthrtut.pod
字号:
$thr->detach(); # Now we officially don't care any more sleep(15); # Let thread run for awhile sub sub1 { $a = 0; while (1) { $a++; print("\$a is $a\n"); sleep(1); } }Once a thread is detached, it may not be joined, and any return datathat it might have produced (if it was done and waiting for a join) islost.C<detach()> can also be called as a class method to allow a thread todetach itself: use threads; my $thr = threads->create(\&sub1); sub sub1 { threads->detach(); # Do more work }=head2 Process and Thread TerminationWith threads one must be careful to make sure they all have a chance torun to completion, assuming that is what you want.An action that terminates a process will terminate I<all> runningthreads. die() and exit() have this property,and perl does an exit when the main thread exits,perhaps implicitly by falling off the end of your code,even if that's not what you want.As an example of this case, this code prints the message"Perl exited with active threads: 2 running and unjoined": use threads; my $thr1 = threads->new(\&thrsub, "test1"); my $thr2 = threads->new(\&thrsub, "test2"); sub thrsub { my ($message) = @_; sleep 1; print "thread $message\n"; }But when the following lines are added at the end: $thr1->join; $thr2->join;it prints two lines of output, a perhaps more useful outcome.=head1 Threads And DataNow that we've covered the basics of threads, it's time for our nexttopic: Data. Threading introduces a couple of complications to dataaccess that non-threaded programs never need to worry about.=head2 Shared And Unshared DataThe biggest difference between Perl I<ithreads> and the old 5.005 stylethreading, or for that matter, to most other threading systems out there,is that by default, no data is shared. When a new Perl thread is created,all the data associated with the current thread is copied to the newthread, and is subsequently private to that new thread!This is similar in feel to what happens when a UNIX process forks,except that in this case, the data is just copied to a different part ofmemory within the same process rather than a real fork taking place.To make use of threading, however, one usually wants the threads to shareat least some data between themselves. This is done with theL<threads::shared> module and the C<:shared> attribute: use threads; use threads::shared; my $foo :shared = 1; my $bar = 1; threads->create(sub { $foo++; $bar++; })->join(); print("$foo\n"); # Prints 2 since $foo is shared print("$bar\n"); # Prints 1 since $bar is not sharedIn the case of a shared array, all the array's elements are shared, and fora shared hash, all the keys and values are shared. This placesrestrictions on what may be assigned to shared array and hash elements: onlysimple values or references to shared variables are allowed - this isso that a private variable can't accidentally become shared. A badassignment will cause the thread to die. For example: use threads; use threads::shared; my $var = 1; my $svar :shared = 2; my %hash :shared; ... create some threads ... $hash{a} = 1; # All threads see exists($hash{a}) and $hash{a} == 1 $hash{a} = $var; # okay - copy-by-value: same effect as previous $hash{a} = $svar; # okay - copy-by-value: same effect as previous $hash{a} = \$svar; # okay - a reference to a shared variable $hash{a} = \$var; # This will die delete($hash{a}); # okay - all threads will see !exists($hash{a})Note that a shared variable guarantees that if two or more threads try tomodify it at the same time, the internal state of the variable will notbecome corrupted. However, there are no guarantees beyond this, asexplained in the next section.=head2 Thread Pitfalls: RacesWhile threads bring a new set of useful tools, they also bring anumber of pitfalls. One pitfall is the race condition: use threads; use threads::shared; my $a :shared = 1; my $thr1 = threads->create(\&sub1); my $thr2 = threads->create(\&sub2); $thr1->join; $thr2->join; print("$a\n"); sub sub1 { my $foo = $a; $a = $foo + 1; } sub sub2 { my $bar = $a; $a = $bar + 1; }What do you think C<$a> will be? The answer, unfortunately, is I<itdepends>. Both C<sub1()> and C<sub2()> access the global variable C<$a>, onceto read and once to write. Depending on factors ranging from yourthread implementation's scheduling algorithm to the phase of the moon,C<$a> can be 2 or 3.Race conditions are caused by unsynchronized access to shareddata. Without explicit synchronization, there's no way to be sure thatnothing has happened to the shared data between the time you access itand the time you update it. Even this simple code fragment has thepossibility of error: use threads; my $a :shared = 2; my $b :shared; my $c :shared; my $thr1 = threads->create(sub { $b = $a; $a = $b + 1; }); my $thr2 = threads->create(sub { $c = $a; $a = $c + 1; }); $thr1->join; $thr2->join;Two threads both access C<$a>. Each thread can potentially be interruptedat any point, or be executed in any order. At the end, C<$a> could be 3or 4, and both C<$b> and C<$c> could be 2 or 3.Even C<$a += 5> or C<$a++> are not guaranteed to be atomic.Whenever your program accesses data or resources that can be accessedby other threads, you must take steps to coordinate access or riskdata inconsistency and race conditions. Note that Perl will protect itsinternals from your race conditions, but it won't protect you from you.=head1 Synchronization and controlPerl provides a number of mechanisms to coordinate the interactionsbetween themselves and their data, to avoid race conditions and the like.Some of these are designed to resemble the common techniques used in threadlibraries such as C<pthreads>; others are Perl-specific. Often, thestandard techniques are clumsy and difficult to get right (such ascondition waits). Where possible, it is usually easier to use Perlishtechniques such as queues, which remove some of the hard work involved.=head2 Controlling access: lock()The C<lock()> function takes a shared variable and puts a lock on it.No other thread may lock the variable until the variable is unlockedby the thread holding the lock. Unlocking happens automaticallywhen the locking thread exits the block that contains the call to theC<lock()> function. Using C<lock()> is straightforward: This example hasseveral threads doing some calculations in parallel, and occasionallyupdating a running total: use threads; use threads::shared; my $total :shared = 0; sub calc { while (1) { my $result; # (... do some calculations and set $result ...) { lock($total); # Block until we obtain the lock $total += $result; } # Lock implicitly released at end of scope last if $result == 0; } } my $thr1 = threads->create(\&calc); my $thr2 = threads->create(\&calc); my $thr3 = threads->create(\&calc); $thr1->join(); $thr2->join(); $thr3->join(); print("total=$total\n");C<lock()> blocks the thread until the variable being locked isavailable. When C<lock()> returns, your thread can be sure that no otherthread can lock that variable until the block containing thelock exits.It's important to note that locks don't prevent access to the variablein question, only lock attempts. This is in keeping with Perl'slongstanding tradition of courteous programming, and the advisory filelocking that C<flock()> gives you.You may lock arrays and hashes as well as scalars. Locking an array,though, will not block subsequent locks on array elements, just lockattempts on the array itself.Locks are recursive, which means it's okay for a thread tolock a variable more than once. The lock will last until the outermostC<lock()> on the variable goes out of scope. For example: my $x :shared; doit(); sub doit { { { lock($x); # Wait for lock lock($x); # NOOP - we already have the lock { lock($x); # NOOP { lock($x); # NOOP lockit_some_more(); } } } # *** Implicit unlock here *** } } sub lockit_some_more { lock($x); # NOOP } # Nothing happens hereNote that there is no C<unlock()> function - the only way to unlock avariable is to allow it to go out of scope.A lock can either be used to guard the data contained within the variablebeing locked, or it can be used to guard something else, like a sectionof code. In this latter case, the variable in question does not hold anyuseful data, and exists only for the purpose of being locked. In thisrespect, the variable behaves like the mutexes and basic semaphores oftraditional thread libraries.=head2 A Thread Pitfall: DeadlocksLocks are a handy tool to synchronize access to data, and using themproperly is the key to safe shared data. Unfortunately, locks aren'twithout their dangers, especially when multiple locks are involved.Consider the following code: use threads; my $a :shared = 4; my $b :shared = 'foo'; my $thr1 = threads->create(sub { lock($a); sleep(20); lock($b); }); my $thr2 = threads->create(sub { lock($b); sleep(20); lock($a); });This program will probably hang until you kill it. The only way itwon't hang is if one of the two threads acquires both locksfirst. A guaranteed-to-hang version is more complicated, but theprinciple is the same.The first thread will grab a lock on C<$a>, then, after a pause during whichthe second thread has probably had time to do some work, try to grab alock on C<$b>. Meanwhile, the second thread grabs a lock on C<$b>, then latertries to grab a lock on C<$a>. The second lock attempt for both threads will
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -