|
|
< Previous PageNext Page > |
Semaphores and locks are similar, except that with semaphores, more than one thread can be doing a given operation at once. Semaphores are commonly used when protecting multiple indistinct resources. For example, you might use a semaphore to prevent a queue from overflowing its bounds.
Mac OS X uses traditional counting semaphores rather than binary semaphores (which are essentially locks). Mach semaphores obey Mesa semantics—that is, when a thread is awakened by a semaphore becoming available, it is not executed immediately. This presents the potential for starvation in multiprocessor situations when the system is under low overall load because other threads could keep downing the semaphore before the just-woken thread gets a chance to run. This is something that you should consider carefully when writing applications with semaphores.
Semaphores can be used any place where mutexes can occur. This precludes their use in interrupt handlers or within the context of the scheduler, and makes it strongly discouraged in the VM system. The public API for semaphores is divided between the MIG–generated task.h
file (located in your build output directory, included with #include <mach/task.h>
) and osfmk/mach/semaphore.h
(included with #include <mach/semaphore.h>
).
The public semaphore API includes the following functions:
kern_return_t semaphore_create(task_t task, semaphore_t *semaphore, |
int policy, int value) |
kern_return_t semaphore_signal(semaphore_t semaphore) |
kern_return_t semaphore_signal_all(semaphore_t semaphore) |
kern_return_t semaphore_wait(semaphore_t semaphore) |
kern_return_t semaphore_destroy(task_t task, semaphore_t semaphore) |
kern_return_t semaphore_signal_thread(semaphore_t semaphore, |
thread_act_t thread_act) |
which are described in <mach/semaphore.h>
or xnu/osfmk/mach/semaphore.h
(except for create and destroy, which are described in <mach/task.h>
.
The use of these functions is relatively straightforward with the exception of the semaphore_create
, semaphore_destroy
, and semaphore_signal_thread
calls.
The value
and semaphore
parameters for semaphore_create
are exactly what you would expect—a pointer to the semaphore structure to be filled out and the initial value for the semaphore, respectively.
The task
parameter refers to the primary Mach task that will “own” the lock. This task should be the one that is ultimately responsible for the subsequent destruction of the semaphore. The task
parameter used when calling semaphore_destroy
must match the one used when it was created.
For communication within the kernel, the task
parameter should be the result of a call to current_task
. For synchronization with a user process, you need to determine the underlying Mach task for that process by calling current_task
on the kernel side and mach_task_self
on the application side.
task_t current_task(void); // returns the kernel task port |
task_t mach_task_self(void);// returns the task port of the current thread |
Note: In the kernel, be sure to always use current_task
. In the kernel, mach_task_self
returns a pointer to the kernel’s VM map, which is probably not what you want.
The details of user-kernel synchronization are beyond the scope of this document.
The policy
parameter is passed as the policy for the wait queue contained within the semaphore. The possible values are defined in osfmk/mach/sync_policy.h
. Current possible values are:
The FIFO policy is, as the name suggests, first-in-first-out. The fixed priority policy causes wait queue reordering based on fixed thread priority policies. The prepost policy causes the
semaphore_signal
function to not increment the counter if no threads are waiting on the queue. This policy is needed for creating condition variables (where a thread is expected to always wait until signalled). See the section “Wait Queues and Wait Primitives” for more information.
The semaphore_signal_thread
call takes a particular thread from the wait queue and places it back into one of the scheduler’s wait-queues, thus making that thread available to be scheduled for execution. If thread_act
is NULL
, the first thread in the queue is similarly made runnable.
With the exception of semaphore_create
and semaphore_destroy
, these functions can also be called from user space via RPC. See “Calling RPC From User Applications” for more information.
< Previous PageNext Page > |
Last updated: 2006-11-07
|
Get information on Apple products.
Visit the Apple Store online or at retail locations. 1-800-MY-APPLE Copyright © 2007 Apple Inc. All rights reserved. | Terms of use | Privacy Notice |