📄 perlothrtut.pod
字号:
=head1 NAMEperlothrtut - old tutorial on threads in Perl=head1 DESCRIPTIONB<WARNING>:This tutorial describes the old-style thread model that was introduced inrelease 5.005. This model is deprecated, and has been removedfor version 5.10. The interfaces described here were consideredexperimental, and are likely to be buggy.For information about the new interpreter threads ("ithreads") model, seethe F<perlthrtut> tutorial, and the L<threads> and L<threads::shared>modules.You are strongly encouraged to migrate any existing threads code to thenew model as soon as possible.=head1 What Is A Thread Anyway?A thread is a flow of control through a program with a singleexecution point.Sounds an awful lot like a process, doesn't it? Well, it should.Threads are one of the pieces of a process. Every process has at leastone thread and, up until now, every process running Perl had only onethread. With 5.005, though, you can create extra threads. We're goingto show you how, when, and why.=head1 Threaded Program ModelsThere are three basic ways that you can structure a threadedprogram. Which model you choose depends on what you need your programto do. For many non-trivial threaded programs you'll need to choosedifferent models for different pieces of your program.=head2 Boss/WorkerThe boss/worker model usually has one `boss' thread and one or more`worker' threads. The boss thread gathers or generates tasks that needto be done, then parcels those tasks out to the appropriate workerthread.This model is common in GUI and server programs, where a main threadwaits for some event and then passes that event to the appropriateworker threads for processing. Once the event has been passed on, theboss thread goes back to waiting for another event.The boss thread does relatively little work. While tasks aren'tnecessarily performed faster than with any other method, it tends tohave the best user-response times.=head2 Work CrewIn the work crew model, several threads are created that doessentially the same thing to different pieces of data. It closelymirrors classical parallel processing and vector processors, where alarge array of processors do the exact same thing to many pieces ofdata.This model is particularly useful if the system running the programwill distribute multiple threads across different processors. It canalso be useful in ray tracing or rendering engines, where theindividual threads can pass on interim results to give the user visualfeedback.=head2 PipelineThe pipeline model divides up a task into a series of steps, andpasses the results of one step on to the thread processing thenext. Each thread does one thing to each piece of data and passes theresults to the next thread in line.This model makes the most sense if you have multiple processors so twoor more threads will be executing in parallel, though it can oftenmake sense in other contexts as well. It tends to keep the individualtasks small and simple, as well as allowing some parts of the pipelineto block (on I/O or system calls, for example) while other parts keepgoing. If you're running different parts of the pipeline on differentprocessors you may also take advantage of the caches on eachprocessor.This model is also handy for a form of recursive programming where,rather than having a subroutine call itself, it instead createsanother thread. Prime and Fibonacci generators both map well to thisform of the pipeline model. (A version of a prime number generator ispresented later on.)=head1 Native threadsThere are several different ways to implement threads on a system. Howthreads are implemented depends both on the vendor and, in some cases,the version of the operating system. Often the first implementationwill be relatively simple, but later versions of the OS will be moresophisticated.While the information in this section is useful, it's not necessary,so you can skip it if you don't feel up to it.There are three basic categories of threads-user-mode threads, kernelthreads, and multiprocessor kernel threads.User-mode threads are threads that live entirely within a program andits libraries. In this model, the OS knows nothing about threads. Asfar as it's concerned, your process is just a process.This is the easiest way to implement threads, and the way most OSesstart. The big disadvantage is that, since the OS knows nothing aboutthreads, if one thread blocks they all do. Typical blocking activitiesinclude most system calls, most I/O, and things like sleep().Kernel threads are the next step in thread evolution. The OS knowsabout kernel threads, and makes allowances for them. The maindifference between a kernel thread and a user-mode thread isblocking. With kernel threads, things that block a single thread don'tblock other threads. This is not the case with user-mode threads,where the kernel blocks at the process level and not the thread level.This is a big step forward, and can give a threaded program quite aperformance boost over non-threaded programs. Threads that blockperforming I/O, for example, won't block threads that are doing otherthings. Each process still has only one thread running at once,though, regardless of how many CPUs a system might have.Since kernel threading can interrupt a thread at any time, they willuncover some of the implicit locking assumptions you may make in yourprogram. For example, something as simple as C<$a = $a + 2> can behaveunpredictably with kernel threads if $a is visible to otherthreads, as another thread may have changed $a between the time itwas fetched on the right hand side and the time the new value isstored.Multiprocessor Kernel Threads are the final step in threadsupport. With multiprocessor kernel threads on a machine with multipleCPUs, the OS may schedule two or more threads to run simultaneously ondifferent CPUs.This can give a serious performance boost to your threaded program,since more than one thread will be executing at the same time. As atradeoff, though, any of those nagging synchronization issues thatmight not have shown with basic kernel threads will appear with avengeance.In addition to the different levels of OS involvement in threads,different OSes (and different thread implementations for a particularOS) allocate CPU cycles to threads in different ways.Cooperative multitasking systems have running threads give up controlif one of two things happen. If a thread calls a yield function, itgives up control. It also gives up control if the thread doessomething that would cause it to block, such as perform I/O. In acooperative multitasking implementation, one thread can starve all theothers for CPU time if it so chooses.Preemptive multitasking systems interrupt threads at regular intervalswhile the system decides which thread should run next. In a preemptivemultitasking system, one thread usually won't monopolize the CPU.On some systems, there can be cooperative and preemptive threadsrunning simultaneously. (Threads running with realtime prioritiesoften behave cooperatively, for example, while threads running atnormal priorities behave preemptively.)=head1 What kind of threads are perl threads?If you have experience with other thread implementations, you mightfind that things aren't quite what you expect. It's very important toremember when dealing with Perl threads that Perl Threads Are Not XThreads, for all values of X. They aren't POSIX threads, orDecThreads, or Java's Green threads, or Win32 threads. There aresimilarities, and the broad concepts are the same, but if you startlooking for implementation details you're going to be eitherdisappointed or confused. Possibly both.This is not to say that Perl threads are completely different fromeverything that's ever come before--they're not. Perl's threadingmodel owes a lot to other thread models, especially POSIX. Just asPerl is not C, though, Perl threads are not POSIX threads. So if youfind yourself looking for mutexes, or thread priorities, it's time tostep back a bit and think about what you want to do and how Perl cando it.=head1 Threadsafe ModulesThe addition of threads has changed Perl's internalssubstantially. There are implications for people who writemodules--especially modules with XS code or external libraries. Whilemost modules won't encounter any problems, modules that aren'texplicitly tagged as thread-safe should be tested before being used inproduction code.Not all modules that you might use are thread-safe, and you shouldalways assume a module is unsafe unless the documentation saysotherwise. This includes modules that are distributed as part of thecore. Threads are a beta feature, and even some of the standardmodules aren't thread-safe.If you're using a module that's not thread-safe for some reason, youcan protect yourself by using semaphores and lots of programmingdiscipline to control access to the module. Semaphores are coveredlater in the article. Perl Threads Are Different=head1 Thread BasicsThe core Thread module provides the basic functions you need to writethreaded programs. In the following sections we'll cover the basics,showing you what you need to do to create a threaded program. Afterthat, we'll go over some of the features of the Thread module thatmake threaded programming easier.=head2 Basic Thread SupportThread support is a Perl compile-time option-it's something that'sturned on or off when Perl is built at your site, rather than whenyour programs are compiled. If your Perl wasn't compiled with threadsupport enabled, then any attempt to use threads will fail.Remember that the threading support in 5.005 is in beta release, andshould be treated as such. You should expect that it may not functionentirely properly, and the thread interface may well change somebefore it is a fully supported, production release. The beta versionshouldn't be used for mission-critical projects. Having said that,threaded Perl is pretty nifty, and worth a look.Your programs can use the Config module to check whether threads areenabled. If your program can't run without them, you can say somethinglike: $Config{usethreads} or die "Recompile Perl with threads to run this program.";A possibly-threaded program using a possibly-threaded module mighthave code like this: use Config; use MyMod; if ($Config{usethreads}) { # We have threads require MyMod_threaded; import MyMod_threaded; } else { require MyMod_unthreaded; import MyMod_unthreaded; } Since code that runs both with and without threads is usually prettymessy, it's best to isolate the thread-specific code in its ownmodule. In our example above, that's what MyMod_threaded is, and it'sonly imported if we're running on a threaded Perl.=head2 Creating ThreadsThe Thread package provides the tools you need to create newthreads. Like any other module, you need to tell Perl you want to useit; use Thread imports all the pieces you need to create basicthreads.The simplest, straightforward way to create a thread is with new(): use Thread; $thr = Thread->new( \&sub1 ); sub sub1 { print "In the thread\n"; }The new() method takes a reference to a subroutine and creates a newthread, which starts executing in the referenced subroutine. Controlthen passes both to the subroutine and the caller.If you need to, your program can pass parameters to the subroutine aspart of the thread startup. Just include the list of parameters aspart of the C<Thread::new> call, like this: use Thread; $Param3 = "foo"; $thr = Thread->new( \&sub1, "Param 1", "Param 2", $Param3 ); $thr = Thread->new( \&sub1, @ParamList ); $thr = Thread->new( \&sub1, qw(Param1 Param2 $Param3) ); sub sub1 { my @InboundParameters = @_; print "In the thread\n"; print "got parameters >", join("<>", @InboundParameters), "<\n"; }The subroutine runs like a normal Perl subroutine, and the call to newThread returns whatever the subroutine returns.The last example illustrates another feature of threads. You can spawnoff several threads using the same subroutine. Each thread executesthe same subroutine, but in a separate thread with a separateenvironment and potentially separate arguments.The other way to spawn a new thread is with async(), which is a way tospin off a chunk of code like eval(), but into its own thread: use Thread qw(async); $LineCount = 0; $thr = async { while(<>) {$LineCount++} print "Got $LineCount lines\n"; }; print "Waiting for the linecount to end\n"; $thr->join; print "All done\n";You'll notice we did a use Thread qw(async) in that example. async isnot exported by default, so if you want it, you'll either need toimport it before you use it or fully qualify it asThread::async. You'll also note that there's a semicolon after theclosing brace. That's because async() treats the following block as ananonymous subroutine, so the semicolon is necessary.Like eval(), the code executes in the same context as it would if itweren't spun off. Since both the code inside and after the async startexecuting, you need to be careful with any shared resources. Lockingand other synchronization techniques are covered later.=head2 Giving up controlThere are times when you may find it useful to have a threadexplicitly give up the CPU to another thread. Your threading packagemight not support preemptive multitasking for threads, for example, oryou may be doing something compute-intensive and want to make surethat the user-interface thread gets called frequently. Regardless,there are times that you might want a thread to give up the processor.Perl's threading package provides the yield() function that doesthis. yield() is pretty straightforward, and works like this: use Thread qw(yield async); async { my $foo = 50; while ($foo--) { print "first async\n" } yield; $foo = 50; while ($foo--) { print "first async\n" } }; async { my $foo = 50; while ($foo--) { print "second async\n" } yield; $foo = 50; while ($foo--) { print "second async\n" } };=head2 Waiting For A Thread To ExitSince threads are also subroutines, they can return values. To wait
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -