Register your product to gain access to bonus material or receive a coupon.
With this practical book, you will attain a solid understanding of threads and will discover how to put this powerful mode of programming to work in real-world applications.
The primary advantage of threaded programming is that it enables your applications to accomplish more than one task at the same time by using the number-crunching power of multiprocessor parallelism and by automatically exploiting I/O concurrency in your code, even on a single processor machine. The result: applications that are faster, more responsive to users, and often easier to maintain. Threaded programming is particularly well suited to network programming where it helps alleviate the bottleneck of slow network I/O.
This book offers an in-depth description of the IEEE operating system interface standard, POSIXAE (Portable Operating System Interface) threads, commonly called Pthreads. Written for experienced C programmers, but assuming no previous knowledge of threads, the book explains basic concepts such as asynchronous programming, the lifecycle of a thread, and synchronization. You then move to more advanced topics such as attributes objects, thread-specific data, and realtime scheduling. An entire chapter is devoted to "real code," with a look at barriers, read/write locks, the work queue manager, and how to utilize existing libraries. In addition, the book tackles one of the thorniest problems faced by thread programmers-debugging-with valuable suggestions on how to avoid code errors and performance problems from the outset.
Numerous annotated examples are used to illustrate real-world concepts. A Pthreads mini-reference and a look at future standardization are also included.
Click below for Source Code related to this title:
This file contains all individual code files zipped together:
program.tar.Z
Individual Files:
alarm.c
Download the sample pages (includes Chapter 3 and Index)
List of Example Programs.
Preface.
Intended Audience.
About the Author.
Acknowledgments.
1. Introduction.
The "Bailing Programmers".
Definitions and Terminology.
Asynchronous.
Concurrency.
Uniprocessor and Multiprocessor.
Parallelism.
Thread Safety and Reentrancy.
Concurrency Control Functions.
Asynchronous Programming is Intuitive...
. . . Because Unix is Asynchronous.
. . . Because the World is Asynchronous.
About the Examples in This Book.
Asynchronous Programming, by Example.
the Baseline, Synchronous Version.
A Version Using Multiple Processes.
A Version Using Multiple Threads.
Summary.
Benefits of Threading.
Parallelism.
Concurrency.
Programming Model.
Costs of Threading.
Computing Overhead.
Programming Discipline.
Harder to Debug.
To Thread or Not to Thread?
POSIX Thread Concepts.
Architectural Overview.
Types and Interfaces.
Checking for Errors.
Creating and Using Threads.
The Life of a Thread.
Creation.
Startup.
Running and Blocking.
Termination.
Recycling.
Invariants, Critical Sections, and Predicates.
Mutexes.
Creating and Destroying a Mutex.
Locking and Unlocking a Mutex.
Nonblocking Mutex Locks.
Using Mutexes for Atomicity.
Sizing a Mutex to Fit the Job.
Using More Than One Mutex.
Lock Hierarchy.
Lock Chaining.
Condition Variables.
Creating and Destroying a Condition Variable.
Waiting on a Condition Variable.
Waking Condition Variable Waiters.
One Final Alarm Program.
Memory Visibility Between Threads.
Pipeline.
Work Crew.
Client/Server.
One-Time Initialization.
Attributes Objects.
Mutex Attributes.
Condition Variable Attributes.
Thread Attributes.
Cancellation.
Deferred Cancelability.
Asynchronous Cancelability.
Cleaning Up.
Thread-Specific Data.
Creating Thread-Specific Data.
Using Thread-Specific Data.
Using Destructor Functions.
Realtime Scheduling.
POSIX Realtime Options.
Scheduling Policies and Priorities.
Contention Scope and Allocation Domain.
Problems With Realtime Scheduling.
Priority-Aware Mutexes.
Priority Ceiling Mutexes.
Priority Inheritance Mutexes.
Threads and Kernel Entities.
Many-to-One (User Level).
One-to-One (Kernel Level).
Many-to-Few (Two Level).
Fork.
Fork Handlers.
Exec.
Process Exit.
Stdio.
Flockfile and Funlockfile.
Getchar_Unlocked and Putchar_Unlocked.
Thread-Safe Functions.
User and Terminal Identification.
Directory Searching.
String Token.
Time Representation.
Random Number Generation.
Group and User Database.
Signals.
Signal Actions.
Signal Masks.
Pthread_Kill.
Sigwait and Sigwaitinfo.
Sigev_Thread.
Semaphores: Synchronizing With a Signal-Catching Function.
Extended Synchronization.
Barriers.
Read-Write Locks.
Work Queue Manager.
But What About Existing Libraries?
Modifying Libraries to Be Thread-Safe.
Living With Legacy Libraries.
Avoiding Incorrect Code.
Avoid Relying on "Thread Inertia".
Never Bet Your Mortgage on a Thread Race.
Cooperate to Avoid Deadlocks.
Beware of Priority Inversion.
Never Share Condition Variables Between Predicates.
Sharing Stacks and Related Memory Corrupters.
Avoiding Performance Problems.
Beware of Concurrent Serialization.
Use the Right Number of Mutexes.
Too Many Mutexes Will Not Help.
Never Fight Over Cache Lines.
POSIX 1003.1cn1995 Options.
POSIX 1003.1cn1995 Limits.
POSIX 1003.1cn1995 Interfaces.
Error Detection and Reporting.
Use of Void* Type.
Threads.
Mutexes.
Condition Variables.
Cancellation.
Thread-Specific Data.
Realtime Scheduling.
Fork Handlers.
Stdio.
Thread-Safe Functions.
Signals.
Semaphores.
X/Open Xsh5 [Unix98].
POSIX Options for XSH5.
Mutex Type.
Set Concurrency Level.
Stack Guard Size.
Parallel I/O.
Cancellation Points.
POSIX 1003.1j.
Barriers.
Read-Write Locks.
Spinlocks.
Condition Variable Wait Clock.
Thread Abort.
Posix 1003.14.
The White Rabbit put on his spectacles,
"Where shall I begin, please your Majesty?" he asked.
"Begin at the beginning," the King said, very gravely,
"and go on till you come to the end: then stop."
 ***-
Lewis Carroll, Alice's Adventures in Wonderland
This book is about "threads" and how to use them. "Thread" is just a name for a basic software "thing" that can do work on a computer. A thread is smaller, faster, and more maneuverable than a traditional process. In fact, once threads have been added to an operating system, a "process" becomes just data--address space, files, and so forth--plus one or more threads that do something with all that data.
With threads, you can build applications that utilize system resources more efficiently, that are more friendly to users, that run blazingly fast on multiprocessors, and that may even be easier to maintain. To accomplish all this, you need only add some relatively simple function calls to your code, adjust to a new way of thinking about programming, and leap over a few yawning chasms. Reading this book carefully will, I hope, help you to accomplish all that without losing your sense of humor.
The threads model used in this book is commonly called "Pthreads," or "POSIX threads." Or, more formally (since you haven't yet been properly introduced), the POSIX 1003.1cn1995 standard. I'll give you a few other names later-
but for now, "Pthreads" is all you need to worry about.
As I write this, Sun's Solaris, Digital's Digital UNIX, and SGI's IRIX already support Pthreads. The other major commercial UNIX operating systems will soon have Pthreads as well, maybe even by the time you read this, including IBM's AIX and Hewlett-Packard's HP-UX. Pthreads implementations are also available for Linux and other UNIX operating systems.
In the personal computer market, Microsoft's Win32 API (the primary programming interface to both Windows NT and Windows 95) supports threaded programming, as does IBM's OS/2. These threaded programming models are quite different from Pthreads, but the important first step toward using them productively is understanding concurrency, synchronization, and scheduling. The rest is (more or less) a matter of syntax and style, and an experienced thread programmer can adapt to any of these models.
The threaded model can be (and has been) applied with great success to a wide range of programming problems. Here are just a few:
This book assumes that you are an experienced programmer, familiar with developing code for an operating system in "the UNIX family" using the ANSI C language. I have tried not to assume that you have any experience with threads or other forms of asynchronous programming. The Introduction chapter provides a general overview of the terms and concepts you'll need for the rest of the book. If you don't want to read the Introduction first, that's fine, but if you ever feel like you're "missing something" you might try skipping back to get introduced.
Along the way you'll find examples and simple analogies for everything. In the end I hope that you'll be able to continue comfortably threading along on your own. Have fun, and "happy threading."
I have been involved in the Pthreads standard since it began, although I stayed at home for the first few meetings. I was finally forced to spend a grueling week in the avalanche-proof concrete bunker at the base of Snowbird ski resort in Utah, watching hard-working standards representatives from around the world wax their skis. This was very distracting, because I had expected a standards meeting to be a formal and stuffy environment. As a result of this misunderstanding, I was forced to rent ski equipment instead of using my own.
After the Pthreads standard went into balloting, I worked on additional thread synchronization interfaces and multiprocessor issues with several POSIX working groups. I also helped to define the Aspen threads extensions, which were fast-tracked into X/Open XSH5.
I have worked at Digital Equipment Corporation for (mumble, mumble) years, in various locations throughout Massachusetts and New Hampshire. I was one of the creators of Digital's own threading architecture, and I designed (and implemented much of) the Pthreads interfaces on Digital UNIX 4.0. I have been helping people develop and debug threaded code for more than eight years.
My unofficial motto is "Better Living Through Concurrency." Threads are not sliced bread, but then, we're programmers, not bakers, so we do what we can.
This is the part where I write the stuff that I'd like to see printed, and that my friends and coworkers want to see. You probably don't care, and I promise not to be annoyed if you skip over it-
nbut if you're curious, by all means read on.
No project such as this book can truly be accomplished by a single person, despite the fact that only one name appears on the cover. I could have written a book about threads without any help-
I know a great deal about threads, and I am at least reasonably competent at written communication. However, the result would not have been this book, and this book is better than that hypothetical work could possibly have been.
Thanks first and foremost to my manager Jean Fullerton, who gave me the time and encouragement to write this book on the job-
and thanks to the rest of the DECthreads team who kept things going while I wrote, including Brian Keane, Webb Scales, Jacqueline Berg, Richard Love, Peter Portante, Brian Silver, Mark Simons, and Steve Johnson.
Thanks to Garret Swart who, while he was with Digital at the Systems Research Center, got us involved with POSIX. Thanks to Nawaf Bitar who worked with Garret to create, literally overnight, the first draft of what became Pthreads, and who became POSIX thread evangelist through the difficult period of getting everyone to understand just what the heck this threading thing was all about anyway. Without Garret, and especially Nawaf, Pthreads might not exist, and certainly wouldn't be as good as it is. (The lack of perfection is not their responsibility-
that's the way life is.)
Thanks to everyone who contributed to the design of cma, Pthreads, UNIX98, and to the users of DCE threads and DECthreads, for all the help, thought-provoking discourse, and assorted skin-thickening exercises, including Andrew Birrell, Paul Borman, Bob Conti, Bill Cox, Jeff Denham, Peter Gilbert, Rick Greer, Mike Grier, Kevin Harris, Ken Hobday, Mike Jones, Steve Kleiman, Bob Knighten, Leslie Lamport, Doug Locke, Paula Long, Finnbarr P. Murphy, Bill Noyce, Simon Patience, Harold Seigel, Al Simons, Jim Woodward, and John Zolnowsky.
Many thanks to all those who patiently reviewed the drafts of this book (and even to those who didn't seem so patient at times). Brian Kernighan, Rich Stevens, Dave Brownell, Bill Gallmeister, Ilan Ginzburg, Will Morse, Bryan O'Sullivan, Bob Robillard, Dave Ruddock, Bil Lewis, and many others suggested or motivated improvements in structure and detail-
and provided additional skin-thickening exercises to keep me in shape. Devang Shah and Bart Smaalders answered some Solaris questions, and Bryan O'Sullivan suggested what became the "bailing programmers" analogy.
Thanks to John Wait and Lana Langlois at Addison Wesley Longman, who waited with great patience as a first-time writer struggled to balance writing a book with engineering and consulting commitments. Thanks to Pamela Yee and Erin Sweeney, who managed the book's production process, and to all the team (many of whose names I'll never know), who helped. Thanks to my wife, Anne Lederhos, and our daughters Amy and Alyssa, for all the things for which any writers may thank their families, including support, tolerance, and just being there. And thanks to Charles Dodgson (Lewis Carroll), who wrote extensively about threaded programming (and nearly everything else) in his classic works Alice's Adventures in Wonderland, Through the Looking-Glass, and The Hunting of the Snark.
Dave Butenhof
Dave ButenhofPage xv. Treading into dangerous waters, this is an update rather than a "fix", but it seems useful. The second last paragraph on the page ("As I write this, Sun's Solaris, Digital's Digital UNIX, and SGI's IRIX already support Pthreads...") is pretty outdated. Replace with:
Pthreads interfaces are included with Sun's Solaris; Hewlett-Packard's Tru64 UNIX, OpenVMS, NonStop platform, and HP-UX; IBM's AIX, OS/400, and OS/390; SGI's IRIX; SCO's UnixWare; Apple's Mac OS X; and Linux (any major distribution). There's even an Open Source emulation package that allows you to use portable Pthread interfaces on Win32 systems.
Page 15. In the alarm_fork.c example at the bottom of the page, line 2 (#include <wait.h>) should be:
[2] #include <sys/wait.h>
Page 59. The comment at lines 20 through 23 is incorrect. Where the comment says "with the mutex locked, to give monitor_thread a reasonable chance of running", it should say "with the mutex unlocked":
[22] * with the mutex unlocked, to give monitor_thread a reasonable [23] * chance of running.
Page 107. The final paragraph on the page ("The allowed size of a file name and path name may vary...") is labelled for code example lines 43-44. Change that range to 41-42 as the path_max and name_max variables have been moved into the crew_t structure. This change (which involves additional changes on the following pages) resolves a synchronization issue in the startup sequence of a work crew, and also recognizes that crews working simultaneously on different file systems might conceivably need different values. (I could have resolved the synchronization issue by simply using the system constants NAME_MAX and PATH_MAX, but this is more interesting and involves slightly less change in the code.)
Page 108. Replace lines 41 through 44 of the example as follows, making path_max and name_max fields of the crew_t structure rather than independent global variables.
[41] long path_max; /* Filesystem path limit */ [42] long name_max; /* Filesystem name limit */ [43] } crew_t, *crew_p; [44]
Page 109. The second paragraph, currently labelled 20-23, should be moved after the following paragraph, currently labelled 33-37. The labels are changed to reflect reordering of the code segments they describe, as follows. (Only the labels and paragraph order have changed, but I'm including the full context.)
22-26 This condition variable loop blocks each new crew member until work is made available. 40-43 POSIX is a little ambiguous about the actual size of the struct dirent type. The actual requirement for readdir_r is that you pass the address of a buffer large enough to contain a struct dirent with a name member of at least NAME_MAX bytes. TO ensure that we have enough space, allocate a buffer the size of the system's struct dirent plus the maximum size necessary for a file name on the file system we're using. This may be bigger than necessary, but it hopefully won't be too small.
Page 110. The allocation of the struct dirent is deferred until the work crew is started, because that operation now determines the correct size. This involves moving the current lines 14 through 24 after the current lines 25 through 44. Aside from this reorganization, the only change is to the old line 21 (new line 41), where the reference to the global name_max variable becomes crew->name_max.
[14] status = pthread_mutex_lock (&crew->mutex); [15] if (status != 0) [16] err_abort (status, "Lock crew mutex"); [17] [18] /* [19] * There won't be any work when the crew is created, so wait [20] * until something's put on the queue. [21] */ [22] while (crew->work_count == 0) { [23] status = pthread_cond_wait (&crew->go, &crew->mutex); [24] if (status != 0) [25] err_abort (status, "Wait for go"); [26] } [27] [28] status = pthread_mutex_unlock (&crew->mutex); [29] if (status != 0) [30] err_abort (status, "Unlock mutex"); [31] [32] DPRINTF (("Crew %d starting\n", mine->index)); [33] [34] /* [35] * "struct dirent" is funny, because POSIX doesn't require [36] * the definition to be more than a header for a variable [37] * buffer. Thus, allocate a "big chunk" of memory, and use [38] * it as a buffer. [39] */ [40] entry = (struct dirent*)malloc ( [41] sizeof (struct dirent) + crew->name_max); [42] if (entry == NULL) [43] errno_abort ("Allocating dirent"); [44]
Page 112. Correct line 136 of the example code to use the new path_max field of crew_t:
[136] new_work->path = (char*)malloc (crew->path_max);
Page 117. Correct line 29 of the example code to use the new path_max field of crew_t:
[29] crew->path_max = pathconf (filepath, _PC_PATH_MAX);
Page 118. Correct 9 lines (30, 32, 37, 38, 40, 46, 47, 48, and 53) of the example code to use the new path_max and name_max fields of crew_t. For reference, all of lines 30 through 53 are shown here:
[30] if (crew->path_max == -1) { [31] if (errno == 0) [32] crew->path_max = 1024; /* "No limit" */ [33] else [34] errno_abort ("Unable to get PATH_MAX"); [35] } [36] errno = 0; [37] crew->name_max = pathconf (filepath, _PC_NAME_MAX); [38] if (crew->name_max == -1) { [39] if (errno == 0) [40] crew->name_max = 256; /* "No limit" */ [41] else [42] errno_abort ("Unable to get NAME_MAX"); [43] } [44] DPRINTF (( [45] "PATH_MAX for %s is %ld, NAME_MAX is %ld\n", [46] filepath, crew->path_max, crew->name_max)); [47] crew->path_max++; /* Add null byte */ [48] crew->name_max++; /* Add null byte */ [49] request = (work_p)malloc (sizeof (work_t)); [50] if (request == NULL) [51] errno_abort ("Unable to allocate request"); [52] DPRINTF (("Requesting %s\n", filepath)); [53] request->path = (char*)malloc (crew->path_max);
Page 207. In the flock.c example, each of the 3 inputs are echoed with the label "Thread 1". This makes no sense. I actually fixed these problems just about 4 years ago, along with some type casting problems, but I overlooked the label changes when writing the errata. The labels in lines 69 and 74 should be changed to "Thread 2" and "Thread 3", respectively. For reference, those 2 changed lines are shown with the intervening lines (unchanged) for context:
[69] printf ("Thread 2: \"%s\"\n", (char*)string); [70] free (string); [71] status = pthread_join (thread3, &string); [72] if (status != 0) [73] err_abort (status, "Join thread"); [74] printf ("Thread 3: \"%s\"\n", (char*)string);
Page 241. I'm not quite sure how this could have happened, but it has been pointed out (and I think I've quite carefully verified) that the Mock Turtle quote used here actually comes from Alice's Adventures in Wonderland rather than Through the Looking-Glass. The attribution line should be changed accordingly. In addition, it would be technically correct to remove page 241 from the list of quotes attributed to Through the Looking-Glass on "page vi" immediately preceding the Contents page, and add page 241 to the list of quotes attributed to Alice's Adventures in Wonderland..
On page 244, at the second line in the 5th paragraph, in the sentence beginning "The threshhold member is the number of threads in the group [...]", the actual name (and correct spelling) of the structure member is threshold. Replace threshhold by threshold.
Page 256. The comment at line 2 in the rwlock.h header example is incorrect. "Support static initialization of barriers." should be replaced by "Support static initialization of read-write locks."
Page 278. The workq_server routine failed to maintain the idle count. To make room without changing page breaks, I've compressed two comments, changing line numbers.
Note: Line 31 has changed, and the second line of that comment has been removed. Lines 33 and 36 were added. Lines 43 through 46 have been rewritten (replacing the original lines 42 through 46). Intervening lines are identical except in line number. Lines 30 and 47 have not changed and are included here only for context.[30] /* [31] * Server threads exit after waiting 2 seconds. [32] */ [33] wq->idle++; [34] status = pthread_cond_timedwait ( [35] &wq->cv, &wq->mutex, &timeout); [36] wq->idle--; [37] if (status = ETIMEDOUT) { [38] DPRINTF (("Worker wait timed out\n")); [39] timedout = 1; [40] break; [41] } else if (status != 0) { [42] /* [43] * This should return failure, but that's [44] * awkward because this routine is running [45] * asynchronously. Failure is unlikely, [46] * and I've chosen to avoid that level of [47] * complication. The server thread will return,
Page 297. In the last-but-one line of section 8.1.2 before the 8.1.3 heading, a sentence begins "Refer to crew.c, in Section 4.2...". The "crew.c" should be in fixed-pitch font, however the initial "c" escaped and appears in the normal text font.
Page 315. The function "pthread_exit" is shown as "int pthread_exit", but the "int" should be "void". That is, the prototype for the function should be:
The function pthread_exit() never returns, so prototyping a return value would be pointless!void pthread_exit ( void *value_ptr);
Page 316. The Hint line under pthread_self at the top of the page is ambiguously short and potentially misleading. Change to:
Hint: Use to detach or adjust scheduling of calling thread.
Page 327. Since I fixed pthread_attr_setinheritsched to mention contention scope, I ought to fix pthread_attr_getinheritsched as well. Replace the phrase "using the scheduling policy and parameters of the creator" with "using the scheduling policy, parameters, and contention scope of the creator".
Page 327. The function pthread_attr_getschedparam is designated as appearing under the POSIX option _POSIX_THREAD_PRIORITY_SCHEDULING. While it's not particularly useful without that option, strictly speaking this is incorrect: the function is required of any implementation supporting threads. The notation "[_POSIX_THREAD_PRIORITY_SCHEDULING]" in the leading line, and the string of "." separators that precede it, should be removed, so that the line appears like this:
pthread_attr_getschedparam
Page 329. Somewhere between the 3rd printing (which is fine) and the 7th printing (the next copy I have), most of a paragraph was dropped from the description of the pthread_attr_setinheritsched function. The description now reads:
change the inheritsched attribute from PTHREAD_INHERIT_SCHED to PTHREAD_EXPLICIT_SCHED. The default is implementation defined.But in the 3rd printing, this text was preceded by:
Specify whether threads created with attr will run using the scheduling policy and parameters of the creator or those specified in the attributes object. When you change the scheduling policy or parameters in a thread attributes object, you mustIn looking at it now, I think it's a little odd to tell people to change it from "inherit" to "explicit" (which happens to be how it'd work on most implementations) and then tell them that the default is implementation defined. Also, originally the inheritance of the contention scope wasn't explicitly attached to inheritsched, and nobody really thought about it. In the most recent revision of the standard, this has been fixed. So instead of just restoring the original text, I'd like the paragraph to read:
Specify whether threads created with attr will use the scheduling policy, parameters, and contention scope of the creator or those specified in the attributes object. When you change the scheduling policy, parameters, or contention scope in a thread attributes object, you must set the inheritsched attribute to PTHREAD_EXPLICIT_SCHED. The default value of inheritsched is implementation defined.
Page 329. The function pthread_attr_setschedparam is designated as appearing under the POSIX option _POSIX_THREAD_PRIORITY_SCHEDULING. While it's not particularly useful without that option, strictly speaking this is incorrect: the function is required of any implementation supporting threads. The notation "[_POSIX_THREAD_PRIORITY_SCHEDULING]" in the leading line, and the string of "." separators that precede it, should be removed, so that the line appears like this:
pthread_attr_setschedparam
Page 332. In the header line for the pthread_mutexattr_getprotocol function at the bottom of the page, two separate POSIX option symbols are documented within square brackets. The two symbols got squashed together into one text string, as "[_POSIX_THREAD_PRIO_INHERIT_POSIX_THREAD_PRIO_PROTECT]". They need to be separated, like this:
pthread_mutexattr_getprotocol... [_POSIX_THREAD_PRIO_INHERIT _POSIX_THREAD_PRIO_PROTECT]Page 333. The pthread_mutexattr_setprotocol function has the same problem with the option names being squashed together. The header line should be:
pthread_mutexattr_setprotocol... [_POSIX_THREAD_PRIO_INHERIT _POSIX_THREAD_PRIO_PROTECT]
On page 332, in the reference section for pthread_mutex_setprioceiling, the prototype uses the name pthread_mutex_getprioceiling. The prototype should be:
int pthread_mutex_setprioiceiling ( pthread_mutex_t *mutex, int prioceiling, int *old_ceiling);
Page 338. The prototype for the function getchar_unlocked defines getc_unlocked. The correct prototype should be:
int getchar_unlocked (void);
Page 348. The prototype in the shaded area for the function pthread_getconcurrency is not complete; the argument list should be specified as void, as follows:
int pthread_getconcurrency (void);
Pages 356-361. So far, I've avoided correcting my descriptions of the preliminary UNIX 98 functions, despite changes in the final version. Every time I look at it, (especially as I've yet to find time to think seriously about a revised edition), I get more tempted to take a crack at making simple changes to update the descriptions. I'm going to give it a try. This is going to slightly change page flows, and it affects the index. The effect doesn't seem substantial, but even if Addison-Wesley doesn't want to deal with this in a reprint, it's worth having the information in the errata.
Page 356. The proposed 1003.1j barrier functions listed here use barrier_ prefixes, but the final version reverted to the "standard" Pthread pthread_ prefixes. This is easy to fix, although the list will continue into page 357. (Which may be OK since I'll be deleting some lines there.)
int pthread_barrierattr_init ( pthread_barrierattr_t *attr); int pthread_barrierattr_destroy ( pthread_barrierattr_t *attr); int pthread_barrierattr_getpshared ( const pthread_barrierattr_t *attr, int *pshared); int pthread_barrierattr_setpshared ( pthread_barrierattr_t *attr, int pshared); int pthread_barrier_init (pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, int count); int pthread_barrier_destroy ( pthread_barrier_t *barrier); int pthread_barrier_wait (pthread_barrier_t *barrier);
Page 357. The proposed 1003.1j read-write lock functions used rwlock_ prefixes, but the final version reverted to the "standard" Pthread pthread_ prefixes.
int pthread_rwlockattr_init ( pthread_rwlockattr_t *attr); int pthread_rwlockattr_destroy ( pthread_rwlockattr_t *attr); int pthread_rwlockattr_getpshared ( const pthread_rwlockattr_t *attr, int *pshared); int pthread_rwlockattr_setpshared ( pthread_rwlockattr_t *attr, int pshared); int pthread_rwlock_init (pthread_rwlock_t *rwl, const pthread_rwlockattr_t *attr); int pthread_rwlock_destroy (pthread_rwlock_t *rwl); int pthread_rwlock_rdlock (pthread_rwlock_t *rwl); int pthread_rwlock_timedrdlock (pthread_rwlock_t *rwl, const struct timespec *timeout); int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwl); int pthread_rwlock_unlock (pthread_rwlock_t *rwl); int pthread_rwlock_wrlock (pthread_rwlock_t *rwl); int pthread_rwlock_timedwrlock (pthread_rwlock_t *rwl, const struct timespec *timeout); int pthread_rwlock_trywrlock (pthread_rwlock_t *rwl); int pthread_rwlock_wrlock (pthread_rwlock_t *rwl);
Also on page 357, he proposed 1003.1j spinlock functions were divided into "process private" versions with spin_ prefixes and "process shared" versions with pthread_ prefixes. These were consolidated into one set of pthread_ interfaces using an integer pshared argument on initialization, as for sem_init. The final list of spinlock functions is:
int pthread_spin_init (pthread_spinlock_t *lock, int pshared); int pthread_spin_destroy (pthread_spinlock_t *lock); int pthread_spin_lock (pthread_spinlock_t *lock); int pthread_spin_trylock (pthread_spinlock_t *lock); int pthread_spin_unlock (pthread_spinlock_t *lock);
And the final change for page 357: The proposed 1003.1j function pthread_abort was rejected and removed during balloting. The following lines should be removed from the page:
Thread abort:int pthread_abort (pthread_t thread);
Page 358. The text of section 10.2.2, Read/write locks, is substantially changed by events that occurred after I originally wrote the book. If I'm updating the function definitions, I need to rewrite this section. I'm including the entire section for context; in fact, the first paragraph (of 3) is substantially modified, the 2nd has not changed at all, and only the parenthetical comment at the end of the 3rd has changed. The footnote at the bottom of page 358 ("The POSIX working group is considering...") should be deleted, as it is no longer relevant.
A read/write lock (also sometimes known at "reader/writer lock") allows one thread to exclusively lock some shared data to write or modify that data, but also allows multiple threads to simultaneously lock the data for read access while excluding writers. POSIX.1j reader/writer locks have become part of both POSIX 1003.1-2001 and XSH6 (aka the Single UNIX Specification, Version 3), which are both built from the same document source.If your code relies on a data structure that is frequently referenced, but only occasionally updated, you should consider using a read/write lock rather than a mutex to access that data. Most threads will be able to read the data without waiting; they'll need to block only when some thread is in the process of modifying the data. (Similarly, a thread that desires to write the data will be blocked if any threads are reading the data.)
See Section 7.1.2 for details of a read/write lock behavior and for an example showing how to implement a read/write lock using standard Pthreads synchronization. (Note that the behavior of this example is not precisely the same as the behavior of POSIX read/write locks.)
Page 359. The last two paragraphs of section 10.2.3, Spinlocks, are now substantially wrong because of changes in 1003.1j during late balloting. (Starting with "POSIX.1j contains two sets of spinlock functions: one set with a spin_ prefix, ...", and continuing through the end of section 10.2.3.) Those paragraphs should be replaced by:
There was a general consensus in the working group that attributes objects might impose some form of overhead, and that this should be avoided in an implicitly lightweight operation like "spinlock". After much discussion, the group decided to follow the model of sem_init rather than Pthread mutexes and condition variables (or even barriers and read/write locks), by selecting between "process private" and "process shared" behavior with a single integer parameter rather than a full attributes object.Thus, pthread_spin_init has an "int pshared" argument rather than a set of attributes object functions. This also implies that no additional user control over spinlock behavior can be accomplished without creating new interfaces. Some argue that this is a fine thing, and I will express no opinion on that subject.
Page 361. Delete all of section 10.2.5, including the title. The function pthread_abort was removed during balloting of POSIX 1003.1j and did not become part of the standard.
Page xi. The line "10.2.5 Thread abort" should be removed from the table of contents.
Page 369. The entry "Abort thread, 361" (first entry under "A") should be removed.
Page 374. The entry "pthread_abort (function), 361" in the second column should be removed.
Page 367. The newsgroup comp.unix.osf.osf1 has been shut down, and replaced by comp.unix.tru64, and I may as well update the name of the operating system. Replace that entry as follows:
comp.unix.tru64The primary discussion group for the Tru64 UNIX operating system. This is a reasonable place to ask questions about using threads on Tru64 UNIX (or of course on earlier versions named "Digital UNIX", or even "DEC OSF/1"). If your question (or problem) doesn't seem to be specific to Tru64 UNIX, comp.programming.threads may be more appropriate because it presents your question to a larger audience of thread experts, and makes the answer available to a larger audience of thread users.
Page 368. It's silly to keep the old recommendation for the AltaVista search engine, which has long since had a different address and declining respect. (Sorry, but it's true.) I use google. Doesn't everyone? Replace the first "Web sites" entry (http://altavista.digital.com/) with:
http://www.google.com/The Google search engine is a great place to start searching for everything. (Have you "googled" your own name? My father does this on a regular basis, and once found a speech he'd given that he was unaware had ever been near a computer.) "Google groups" (http://groups.google.com) contains enormous archives of newsgroup postings (a good way to research what you've missed on comp.programming.threads since it began) and lets you read and post news through a web interface.
The http://www.best.com/~bos/threads-faq/ web address given here for Bryan O'Sullivan's threads FAQ (the third entry on the page) hasn't worked for a while, and in any case his FAQ hasn't been updated since 1997. I ought to switch to the Bil Lewis FAQ, which in any case has always been "the official FAQ" of the threads newsgroup:
http://www.lambdacs.com/cpt/cpt.htmlThis page, maintained by Bil Lewis, is filled with useful information. In particular, it contains links to not one, but two FAQ (that's "Frequently Asked Questions") listings. There's the full version (currently about 350 questions), and the short form ("Most Frequently Asked Questions"). There's also a bibliography.
The 5th site, http://www.digital.com, is a pretty old link. While I think it's still intended to work, it doesn't seem to for me. Replace that entry with:
http://www.hp.com/Hewlett-Packard Company web site. It includes everything from Compaq Computer Corporation and Digital Equipment Corporation. If you want information on Tru64 UNIX, OpenVMS, NonStopOS, HP-UX, or a couple of nice printers, this is the place.
The last entry on the page, http://www.netcom.com/~brownell/pthreads++.html, no longer exists. In the spirit of a "token C++ reference", replace it with:
http://www.boost.org/The Boost organization has been working with possible C++ frameworks to better support threaded programming.