Multiprocessing

Dual-processor computers are now a significant part of Apple's hardware product line, and Mac OS X is designed to take advantage of them. If your Win32 application uses threading to take advantage of multiple processors, you can achieve similar performance when you port your application to Mac OS X. This section tells you how to get started.

For your information, Mac OS X supports multiple threading packages, including POSIX threads. (See Chapter 14 of Inside Mac OS X: System Overview for details.) If your Win32 application is already threaded, the Mac OS X API that most closely matches your code may be the Multiprocessing Services API, which is what this section covers.

Mac OS X/Win32 Similarities

Mac OS X and the Win32 platform take similar approaches to their support of multiprocessing, and the APIs involved are similar in structure and design. Here are the major similarities:

Approaches to Porting

There are three ways to port your Win32 threaded code to Mac OS X using the Multiprocessing Services API:

Which one you choose depends, of course, upon the priorities and limitations of your situation.

Before you decide on a porting approach, you should familiarize yourself with the Mac OS X APIs you will be using. As is the case on the Win32 platform, some APIs work in a multithreaded environment, others do not, and still others work if you observe certain restrictions. The issue of multithreading support may force you to change the approach you use to port your application to Mac OS X.

Writing Glue Code

In this approach, you leave your source code unchanged and concentrate on writing glue code that implements your multiprocessing APIs using Multiprocessing Services routines. This way, your code continues to run, believing that it is still operating on a multiple-processor Win32 computer.

The primary advantage of this approach is that if it is implemented correctly, you do not need to modify or retest the application code that uses threads, semaphores, critical sections, and so on. In addition, once you have the glue code working, you can port new Win32 applications to Mac OS X with minimal effort.

There are several significant disadvantages to this approach, however. First, the glue code necessarily introduces some processing overhead, and the ported application may run unacceptably slow. Second, writing the glue code is not a trivial task, and your schedule may not include the time needed to design, implement, and debug it.

Modifying Your Win32 Code

This approach involves leaving your program logic intact but replacing Win32-specific code with Mac OS X code that does the same thing.

The primary advantage of this approach over the glue-code approach is that the resulting code will run faster then it would using glue code. Depending on the complexity and length of your Win32 code, the porting process may be faster and easier.

This approach has two significant disadvantages. First, you will need to retest the ported application code. Second, this approach leaves you with two versions of your source code that must be maintained and enhanced separately.

Rewriting Your Win32 Code

On the Win32 side, the prevailing programming paradigm for multi-threaded applications centers around suspending threads that run too long and killing threads when necessary; these are actions that waste processor time needlessly. Applications that are structured around the producer/consumer model make better use of multithreading on any platform, and you should consider rewriting your Win32 code to use it.

An added advantage to switching to the producer/consumer model is that Mac OS X was designed to work well with it. When a task (thread) blocks, Mac OS X automatically suspends it quickly and with virtually no processor or memory overhead; when a task becomes unblocked, Mac OS X automatically and quickly reactivates it. Task creation and destruction, on the other hand, incur significantly greater overhead.

Tasks are suspended and resumed millions of times over their lifetimes, so these operations should be as efficient as possible. The producer/consumer model, in general, has no need to terminate a thread implementing a producer or consumer prematurely, though it switches tasks often. These two facts, taken together, explain why Mac OS X and the producer/consumer model are such a good fit.

The advantage of converting your program logic to use the producer/consumer model is that your application will run faster and will be easier to maintain on both the Win32 and Mac OS X platforms. The disadvantage is, of course, the time needed to rewrite and debug a major portion of your code.

The Multiprocessing Services API

A Multiprocessing Services task is a preemptively scheduled thread that is layered on top of a POSIX thread. The Multiprocessing Services API includes support for the following:

Event groups help you build code that blocks a thread until one of multiple events occurs. This is an improvement on the Win32 routine WaitForMultipleObjects in that, with an event group, you know which event or events have occurred and can make use of that knowledge.

For Further Information

You can find the the Multiprocessing Services API in the Carbon section of Appleā€™s Developer Documentation website. For your convenience, a link to its page is listed below.

Multiprocessing Services

Multiprocessing Services Reference

books on pthreads

Programming with POSIX Threads, by David R. Butenhof (Addison Wesley, 1997)

POSIX 4: Programming for the Real World, by Bill O. Gallmeister and Mike Loukides (O'Reilly, 1994)