Add Book to My BookshelfPurchase This Book Online

Preface -

Pthreads Programming
Bradford Nichols, Dick Buttlar and Jacqueline Proulx Farrell
 Copyright © 1996 O'Reilly & Associates, Inc.

It's been quite a while since the people from whom we get our project assignments accepted the excuse "Gimme a break! I can only do one thing at a time!" It used to be such a good excuse, too, when things moved just a bit slower and a good day was measured in written lines of code. In fact, today we often do many things at a time. We finish off breakfast on the way into work; we scan the Internet for sports scores and stock prices while our application is building; we'd even read the morning paper in the shower if the right technology were in place!
Being busy with multiple things is nothing new, though. (We'll just give it a new computer-age name, like multitasking, because computers are happiest when we avoid describing them in anthropomorphic terms.) It's the way of the natural world—we wouldn't be able to write this book if all the body parts needed to keep our fingers moving and our brains engaged didn't work together at the same time. It's the way of the mechanical world—we wouldn't have been able to get to this lovely prefabricated office building to do our work if the various, clanking parts of our automobiles didn't work together (most of the time). It's the way of the social and business world—three authoring tasks went into the making of this book, and the number of tasks, all happening at once, grew exponentially as it went into its review cycles and entered production.
Computer hardware and operating systems have been capable of multitasking for years. CPUs using a RISC (reduced instruction set computing) microprocessor break down the processing of individual machine instructions into a number of separate tasks. By pipelining each instruction through each task, a RISC machine can have many instructions in progress at the same time. The end result is the heralded speed and throughput of RISC processors. Time-sharing operating systems have been allowing users nearly simultaneous access to the processor for longer than we can remember. Their ability to schedule different tasks (typically called processes) really pays off when separate tasks can actually execute simultaneously on separate CPUs in a multiprocessor system.
Although real user applications can be adapted to take advantage of a computer's ability to do more than one thing at once, a lot of operating system code must execute to make it possible. With the advent of threads we've reached an ideal state—the ability to perform multiple tasks simultaneously with as little operating system overhead as possible.
Although threaded programming styles have been around for some time now, it's only recently that they've been adopted by the mainstream of UNIX programmers (not to mention those erstwhile laborers in the vineyards of Windows NT and other operating systems). Software sages swear at the lunchroom table that transaction processing monitors and real-time embedded systems have been using thread-like abstractions for more than  twenty years. In the mid-to-late eighties, the general operating system community embarked on several research efforts focused on threaded programming designs, as typified by the work of Tom Doeppner at Brown University and the Mach OS developers at Carnegie-Mellon. With the dawn of the nineties, threads became established in the various UNIX operating systems, such as USL's System V Release 4, Sun Solaris, and the Open Software Foundation's OSF/1. The clash of platform-specific threads programming libraries advanced the need of some portable, platform-independent threads interface.  The IEEE has just this year met this need with the acceptance of the IEEE Standard for Information Technology Portable Operating System Interface  (POSIX) Part 1: System Application Programming Interface (API) Amendment 2: Threads Extension [C Language]—the Pthreads standard, for short. 
This book is about Pthreads—a lightweight, easy-to-use, and portable mechanism for speeding up applications.
We'll start off Chapter 1, Why Threads?, by introducing you to multithreading as a way of performing the many tasks of a program with greater efficiency and speed than would be possible in a serial or multiprocess design. We'll then examine the pitfalls of serial and multiprocess programming, and discuss the concept of potential parallelism, the cornerstone of any decision to write a multitasking program. We'll introduce you to your first Pthreads call—pthread_create—and look at those structures by which a thread is uniquely identified. We'll briefly examine the ways in which multiple threads in the same process exchange data, and we'll highlight some synchronization issues.
We'll continue our discussion of planning and structuring a multithreaded program in Chapter 2, Designing Threaded Programs. Here, we'll look at the types of applications that can benefit most from multithreading. We'll present the three classic methods for distributing work among threads—the boss/worker model, the peer model, and the pipeline model. We'll also compare two strategies for creating threads—creation on demand versus thread pools. After a brief discussion of thread data-buffering techniques, we'll introduce the ATM server application example that we'll use as the proving ground for thread concepts we'll examine throughout the rest of the book.
In Chapter 3, Synchronizing Pthreads, we'll look at the tools that the Pthreads library provides to help you ensure that threads access shared data in an orderly manner. This chapter includes lengthy discussions of mutex variables and condition variables, the two primary Pthreads synchronization tools. It also describes reader/writer locks, a more complex synchronization tool built from mutexes and condition variables. By the end of the chapter, we will have added synchronization to our ATM server example and presented most of what you'll need to know to write a working multithreaded program.
We'll look at the special characteristics of threads and the more advanced features of the Pthreads library in Chapter 4, Managing Pthreads. We'll cover some large topics, such as keys (a very handy way for threads to maintain private copies of shared data) and cancellation (a practical method for allowing your threads to be terminated asynchronously without disturbing the state of your program's data and locks). We'll cover some smaller topics, such as thread attributes, including the one that governs the persistence of a thread's internal state. (When you get to this chapter, we promise that you'll know what this means, and you may even value it!) A running theme of this chapter are the various tools that, when combined, allow you to control thread scheduling policies and priorities. You'll find these discussions especially important if your program includes one or more real-time threads.
In Chapter 5, Pthreads and UNIX, we'll describe how multithreaded programs interact with features of the UNIX operating system that many serial programs take for granted. First, we'll examine the special challenges UNIX signals pose to multithreaded programs; we'll look at the types of signals threads must worry about and how you can direct certain signals to specific threads. We'll then focus on the requirements the Pthreads library imposes on system calls and libraries to allow them to work correctly when multiple threads from the same process are using them at the same time. Finally, we'll show you what the UNIX fork and exec calls do to threads. (It isn't always pretty.)
After we've dealt with the fundamentals of Pthreads programming in the earlier chapters, we turn to the more basic issues you'll face in deploying a multithreaded application in Chapter 6, Practical Considerations. The theme of this chapter is speed. We'll look at those performance concerns over which you have little control—those that are inherent in a given platform's Pthreads implementation. Here, we'll profile the three major ways implementors design a Pthreads-compliant platform, listing the advantages and drawbacks of each. We'll move on to a discussion of debugging threads, where we'll illustrate a number of debugging strategies using a thread-capable debugger. Finally, we'll look at various alternatives for improving our program's performance. We'll run some tests on various versions of our ATM server to test their performance as contention and workload increase.
We've also included three brief appendixes:
 Appendix A, Pthreads and DCE, shows how a multithreaded program might be written using the Open Software Foundation's Distributed Computing Environment (DCE).
 Appendix B, Pthreads Draft 4 vs. the Final Standard, lists the differences between Draft 4 of the Pthreads standard and Draft 10, its final version.
 Appendix C, Pthreads Quick Reference, is meant to help you find the syntax of any Pthreads library call quickly, without the need for another book.

Previous SectionNext Section, Inc © 2000 –  Feedback