Pthreads Programming
Pthreads Programming
Pthreads Programming
Agenda
We're going to cover fundamental concepts of multi-threaded programming and Pthreads. We'll play around with some simple C programs, that utilize Pthreads, to learn the basics and to illustrate some important concepts. Due to time limitation, we may not be able to tal about some of the finer points of Pthreads programming. !his is not a comprehensive tutorial. !he goal is to get you "uic ly familiar with multi-threaded programming concepts and Pthreads programming. #f you haven't wor ed with threads before, this tutorial should serve as a good starting point. #f you are more e$perienced, you may or may not benefit from this tutorial% there will be some discussion that may interest those of you with nowledge and e$perience of the topic. !his set of slides will serve as our guide. &nce we get to the e$ample programs the activity will also involve actually running and changing the programs, in order to have some fun and see first-hand how Pthreads actually wor .
Background
Concurrent systems and multi-threaded programming have been with us a number of years.
'ecent developments (clusters, multi-core microprocessors) have led to renewed interest in concurrent programming.
*un +icrosystems ,iagara - ./ cores #0+ Cell 0roadband 1ngine (C01) - up to 2 cores Paralla$ Propeller Chip - 3 cores #ntel Core / Duo, 4uad Core - / and 5 cores 6+D Dual Core (soon to release "uad core)
Background
#n the past, support for concurrent programming was uneven among vendors. Concurrent programming environments and tools were mostly confined to specialized applications.
'eal-time operating systems, in particular, strongly supported concurrent programming, due in some cases to a lac of memory protection. +any real-time systems also demand pea responsiveness.
,ot all software benefits from concurrency. Profile your application. Consider the cost:benefits.
0loc ing or waiting is fre"uent and tas s independent of those in the wait state are critical.
=our program needs to feel responsive to users. 1ven a simple program with a graphical user interface can benefit from running the >9# in a separate thread. !here is a nice e$ample of this in the &''eilly Python Coo boo , where a ! in er >9# runs in a separate thread.
Process Model
6pplication distributed across multiple processes.
9ni$ a great platform for Process +odel applications, due to a good set of interprocess functionality (shared memory, semaphores, process control)
hreading Model
Parallelism achieved within a single process.
6dvantages; <ess time to conte$t switch. Cleaner synta$ (in my opinion). Creating a thread is faster than creating a process. <ess memory usage than multiple processes. 6 threaded process is easier to manage.
@ernel *pace !hreads (7@ernel !hreads8); Controlled only by ernel scheduler. When supported well by the &*, the better way to implement threading.
hreads in %inu&
&riginal <inu$!hreads library was bro en and not fully P&*#A compliant.
,e$t >eneration P&*#A !hreads (,>P!) was offered as a replacement for <inu$!hreads.
,ative P&*#A !hread <ibrary (,P!<) was introduced in /BB., along with ernel modification. 4uic ly became the new <inu$ ernel library. <inu$ now supports Pthreads in the ernel. 9lrich Drepper and #ngo +olnar of 'ed Cat were the heroes behind ,P!<.
'endor Support
#n D22E, a P&*#A standard, PDBB..Dc ( nown as 7Pthreads8) was issued, to standardize multi-threaded programming. !his standard has largely remained the same, with some minor changes.
<inu$ supports threading well. Cey, this is &*C&,G Who cares about proprietary operating systemsHG (especially those posing as open) *o let's Iust use <inu$ (&.@., maybe 0*D or +ac &* A.) # feel better alreadyG
Current rends in Multi( hreaded Programming &pen+P (www.openmp.org) is a tool it that aims to simplify multi-threaded programming in C:CJJ and K&'!'6,.
*ome compilers now have switches that cause generation of parallel code, without re"uiring any special programming by the developer. *un +icrosystems has this in their C:CJJ compiler. *un's motto is 7let the compiler handle the complications of producing multi-threaded code.8
!ransactional +emory is a techni"ue to Iournal memory #:&, which promises to alleviate some of the potential pitfalls of multi-threaded programming. !here will be a short tal about this on Wednesday, 2;.Bam-2;5Epm, Portland 0allroom.
!he >,9 organization has developed a library for C, called >,9 Pth (for >,9 Portable !hreads, see www.gnu.org:software:pth). Pth was a foundation of the abandoned ,>P! proIect.
>,9 also has their own &pen+P proIect (called >&+P,) which appears to be inactive at this time.
6 new &''eilly boo has Iust been released, titled #ntel !hreading 0uilding 0loc s.
!00 is only available for #ntel processors and those that emulate them (i.e. 6+D). #ntel may open-source !00, in which case you will be able to rebuild it for different platforms.
#f #ntel open-sources !00, be sure to chec whether critical performance functionality has been moved into the #ntel compilers. 6lso carefully chec licensing.
Comple$ity doesn't go away, it Iust gets e$pressed differently. #n terms of coding, !00 is in some ways more comple$ than wor ing with Pthreads.
Pthreads
Why Pthreads?
Pthreads is a good way to start learning about concurrent programming.
<inu$ supports Pthreads well and is getting better. !he recently released /.L.// <inu$ ernel improves thread performance.
Why Pthreads?
Pthreads get the Iob done. 1$amples of successful Pthreads applications; 6pache +y*4<
+y*4< is perhaps the strongest endorsement for Pthreads. Pthreads get the Iob done, and do it well, for this high-performance database.
Pthread Attributes
creation scheduling synchronization (mute$es, read:write loc s, semaphores, condition variables) data access ( eys) signal delivery and handling cancellation M destruction
pthread/create*+
#include <pthread.h> pthread_t m"_thread# pthread_attr_t thd_attri # pthread_create($m"_thread% $thd_attri % $m"_function% $parameter)# !oid m"_function(& parameter) ' // do some stuff... ( 'arameters are (assed by re)erence, so i) you need to (ass multi(le (arameters to your )unction, you must (lace them in a structure and (ass a (ointer to it. *he thread handle +my,thread- is used )or all subse.uent re)erences to the thread. *he attribute (arameter +2nd (arameter- can be /0LL, or a (thread,attr,t 1ariable that has been initiali2ed and set. *his is how the (riority and schedulin3 attributes o) a thread are set.
our/include/file#h
// )he important header is pthread.h% #include <pthread.h> // ,-._/0_)123456 controls ho7 man" threads our examples 7ill create. #define NUM_OF_THREADS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include <stdio.h> <stdli .h> <strin8.h> <unistd.h> <si8nal.h> <fcntl.h> <s"s/t"pes.h> <s"s/stat.h> <s"s/soc9et.h> <netd .h> <s"s/un.h> <s"s/ipc.h> <s"s/shm.h> <netinet/in.h> <s"slo8.h> ut let*s include a unch of stuff+
pthreads/0#c
#include :our_include_file.h: !oid m"_function(int &)# int main() ' int num er_of_threads ; ,-._/0_)123456# pthread_t thread_handle!NUM_OF_THREADS"# int thread_id<,-._/0_)123456=# int i# for (i ; ># i < num er_of_threads# i??) ' thread_id<i= ; i# pthread_create$%thread_handle!i"& NU''& $()id *+ ,-_functi)n& $int *+ %thread_id!i"+# // 7e should call pthread_detach() here% ut 7e don*t to sho7 the // pro8ram 7ill 7or9 an"7a" ( ut ma" end up not releasin8 s"stem resources.) ( for(##) ' // if 7e don*t 8o into this loop% the pro8ram 7ill exit // child threads ha!e completed their jo s. ( ( // end main() !oid m"_function(int &m"_thread_id) ' printf(:1ello from thread #@i!An:% &m"_thread_id)# ( // end m"_function() efore the
Compilation
Ncc -pthread -o pthreadOtest pthread.c - or Ncc -lpthread -o pthreadOtest pthread.c !hen, try running it; N.:pthreadOtest
Basic Synchroni1ation
pthreadOIoin() Calling thread waits for Ioined thread to terminate.
#f you don't call pthreadOIoin(), you need to call pthreadOdetach(), which also frees thread resources.
pthreads/2#c
#include :our_include_file.h: !oid m"_function(int &)# int main() ' int num er_of_threads ; ,-._/0_)123456# pthread_t thread_handle<,-._/0_)123456=# int thread_id<,-._/0_)123456=# int i# for (i ; ># i < num er_of_threads# i??) ' thread_id<i= ; i# pthread_create($thread_handle<i=% ,-BB% (!oid &) m"_function% (int &) $thread_id<i=)# pthread_.)in$thread_handle!i"& NU''+# ( // in this example% the calls to pthread_join() 7ait for the child threads // to complete% so 7e don*t put the main thread into an endless loop. ( // end main() !oid m"_function(int &m"_thread_id) ' printf(:1ello from thread #@i!An:% &m"_thread_id)# ( // end m"_function()
pthreads/3(0#c
/// ,o7% the threads 7ill collecti!el" perform a calculation #include :our_include_file.h: !oid m"_function(int &)# int result ; ># int main() ' int num er_of_threads ; ,-._/0_)123456# pthread_t thread_handle<,-._/0_)123456=# int inte8er_!alue<,-._/0_)123456=# int i# for (i ; ># i < num er_of_threads# i??) ' inte8er_!alue<i= ; i# pthread_create($thread_handle<i=% ,-BB% (!oid &) m"_function% (int &) $inte8er_!alue<i=)# pthread_.)in$thread_handle!i"& NU''+# ( printf(:)he calculation result is+ @iAn:% result)# ( // end main() !oid m"_function(int &m"_inte8er_!alue) ' re/ult 01 *,-_inte2er_(alue# ( // end m"_function()
pthreads/3(2#c
/// Ce no7 use a Dthread arrier to s"nchroniEe the threads #include :our_include_file.h: !oid m"_function(int &)# int result ; ># pthread_3arrier_t 3arrier# int main() ' int num er_of_threads ; ,-._/0_)123456# pthread_t thread_handle<,-._/0_)123456=# int inte8er_!alue<,-._/0_)123456=# int i# lon8 expected_result# pthread_3arrier_init$ %3arrier& NU''& $ nu,3er_)f_thread/ 0 4 + +# for (i ; >% expected_result ; ># i < num er_of_threads# expected_result ?; i% i?? ) ' inte8er_!alue<i= ; i# pthread_create($thread_handle<i=% ,-BB% (!oid &) m"_function% (int &) $inte8er_!alue<i=)# pthread_detach$thread_handle!i"& NU''+# ( pthread_3arrier_5ait$%3arrier+# printf(:)he calculation expected result is+ @iAn:% expected_result)# printf(:)he calculation actual result is+ @iAn:% result)#
pthreads/3(2#c *cont#+
pthread_3arrier_de/tr)-$%3arrier+# pthread_exit(,-BB)# ( // end main() !oid m"_function(int &m"_inte8er_!alue) ' result ?; &m"_inte8er_!alue# pthread_3arrier_5ait$%3arrier+# ( // end m"_function()
pthreads/3(3#c
// Ce ha!en*t protected the result !aria le in the pre!ious examples. // ,o7% 7e 7ill protect result, usin8 a Dthread .utex loc9. #include :our_include_file.h: !oid m"_function(int &)# lon8 result ; ># pthread_ arrier_t arrier# pthread_,ute6_t )ur_,ute6# int main() ' int num er_of_threads ; ,-._/0_)123456# pthread_t thread_handle<,-._/0_)123456=# int inte8er_!alue<,-._/0_)123456=# int i# lon8 expected_result# pthread_ arrier_init( $ arrier% ,-BB% ( num er_of_threads ? F ) )# pthread_,ute6_init$%)ur_,ute6& NU''+# for (i ; >% expected_result ; ># i < num er_of_threads# expected_result ?; i% i?? ) ' inte8er_!alue<i= ; i# pthread_create($thread_handle<i=% ,-BB% (!oid &) m"_function% (int &) $inte8er_!alue<i=)# pthread_detach(thread_handle<i=)# ( // end for pthread_ arrier_7ait($ arrier)#
pthreads/3(3#c *cont#+
printf(:)he calculation expected result is+ @iAn:% expected_result)# printf(:)he calculation actual result is+ @iAn:% result)# pthread_ arrier_destro"($ arrier)# pthread_,ute6_de/tr)-$%)ur_,ute6+# pthread_exit(,-BB)# ( // end main() !oid m"_function(int &m"_inte8er_!alue) ' pthread_,ute6_l)c7$%)ur_,ute6+# result ?; &m"_inte8er_!alue# pthread_,ute6_unl)c7$%)ur_,ute6+# pthread_ arrier_7ait($ arrier)# pthread_exit((!oid&) >)# ( // end m"_function()
Shared .ata
*hared data is the bugaboo of parallel programming. =ou'll encounter constant warnings to avoid e$cessive shared data reads. >et over it. 6ll computer systems share resources, in different areas. =es, you should minimize shared data access, but at some point your threads will need to share some data. While on the subIect of shared data...
)BM Cell Broadband 4ngine *CB45 or the 6Cell7+ #0+ has ta en a hybrid approach to programming C01, adding a library with functions applying to the *P1's. 1ach *P1 has dedicated memory. !his greatly reduces the need for threads to share physical memory.
Parallel networ interface controllers *imultaneous memory access Dedicated memory for e$ecution cores
1ven so, there are always going to be bottlenec s, there is no way to escape this. !he way to minimize the effect of bottlenec s is to increase processing speed at bottlenec points. !hus, system design becomes an e$ercise in balancing bandwidth and concurrency.
!hread *cheduling !hread Cancellation !est harnesses for our programs Debugging with >,9 gdb Condition Fariables Process resources and thread attributes Cleanup functions !hread cancellation *cheduling Pthreads *etting process resources
Summary
. P hours is only enough time to introduce the topic and loo at some simple Pthreads e$amples. Pthreads programming is "uite different than se"uential programming. #t involves thin ing a bit differently about what is happening with your code and is also a bit tric y. +any people are comparing concurrent programming to obIect-oriented programming, in that it re"uires a change of thin ing to accommodate the paradigm shift. # thin this is a good analogy. Despite uneven implementation among vendors, Pthreads is proven technology that powers some of the most pervasive and successful infrastructure software.
Summary *cont#+
&f course, Pthreads isn't for everyone. #f you enIoy (out of either pleasure or necessity) the advantages of wor ing with dynamic languages, then by all means continue wor ing with them. =our programs can still benefit from the threading mechanisms of those languages. *ome people have developed Python e$tensions, written in C, that allow them to access Pthreads from their Python programs. !hose of you developing server software, demanding high performance, should definitely ta e a close loo at Pthreads. Download +y*4< source code and see how they have harnessed Pthreads. #f your software is mathematically intensive, you should ta e a loo at #ntel !hreading 0uilding 0loc s (!00).