In Mac OS X, threads are a low-level way to facilitate multiple streams of execution in a single application. Although not as sophisticated as operation objects, threads are a common paradigm on most operating systems and so are familiar to most developers. The following sections describe the thread technologies available in Mac OS X and platform-specific information about those technologies.
Threading Technologies
Thread Costs
Although the underlying implementation mechanism for threads in Mac OS X is Mach threads, you rarely (if ever) work with threads at the Mach level. Instead, you usually use the more convenient POSIX API or one of its derivatives. The Mach implementation does provide the basic features of all threads, however, including a preemptive execution model and the ability to schedule threads so they are independent of each other.
Table 3-1 lists the threading technologies you can use in your applications. This list does not cover thread-related technologies, such as NSOperation, which use threads internally to implement program concurrency. Those technologies are covered in other chapters of this document.
Technology | Description |
|---|---|
Cocoa threads | Cocoa implements threads using the |
POSIX threads | POSIX threads provide a C-based interface for creating threads. If you are not writing a Cocoa application, this is the best choice for creating threads. The POSIX interface is relatively simple to use and offers ample flexibility for configuring your threads. For more information, see “Using POSIX Threads” |
Multiprocessing Services | Multiprocessing Services is a legacy C-based interface used by applications transitioning from older versions of Mac OS. You should avoid using this technology for any new development. Instead, you should use the |
Note: Another threading technology found in some versions of Mac OS X is the Carbon Thread Manager. It is a legacy technology, however, that should not be used for any active development.
Mac OS X supports all of the standard features found in the POSIX threads implementation, including the following:
Thread customization; see “Configuring Threads”
Support for creating threads as joinable or detached; see “Setting the Detached State of a Thread”
Per-thread storage; see “Configuring Thread-Local Storage”
Support for thread cancellation semantics; see “Terminating a Thread”
Threading has a real cost to your program (and the system) in terms of memory use and performance. Each thread in Mac OS X requires the allocation of memory in both the kernel memory space and your program’s memory space. The core structures needed to manage your thread and coordinate its scheduling are stored in the kernel using wired memory. Your thread’s stack space and per-thread data is stored in your program’s memory space. Most of these structures are created and initialized when you first create the thread—a process that can be relatively expensive because of the required interactions with the kernel.
Table 3-2 quantifies the approximate costs associated with creating a new user-level thread in your application. Some of these costs are configurable, such as the amount of stack space allocated for secondary threads. The time-based costs in particular are rough approximations and should be used only for relative comparisons with each other. Things like thread and lock creation times can vary greatly depending on processor load, the speed of the computer, and the amount of available system and program memory.
Note: Because of their underlying kernel support, operation objects can often create threads more quickly. Rather than creating threads from scratch every time, they use pools of threads already residing in the kernel to save on allocation time. For more information about using operation objects, see “Creating and Managing Operation Objects.”
Another cost to consider when writing threaded code is the production costs. Designing a threaded application can sometimes require fundamental changes to the way you organize your application’s data structures. Making those changes might be necessary to avoid the use of synchronization, which can itself impose a tremendous performance penalty on poorly designed applications. Designing those data structures, and debugging problems in threaded code, can increase the time it takes to develop a threaded application. Avoiding those costs can create bigger problems at runtime, however, if your threads spend too much time waiting on locks or doing nothing.
Last updated: 2008-02-08