Re: Run Loops
Re: Run Loops
- Subject: Re: Run Loops
- From: Douglas Davidson <email@hidden>
- Date: Wed, 25 Jul 2001 09:36:48 -0700
On Wednesday, July 25, 2001, at 03:40 AM, Stiphane Sudre wrote:
Hello, where can I find information about run loops. I would like to
read about CFGetRunLoopCurrent() and other related API calls.
The documentation is still forthcoming for the CFRunLoop.h file.
You can create a simple run loop with a timer, a message port listener
from the header but when it comes to creating some complex code, you're
blocked.
It seems (it must be false) that there is only one person at Apple
(D.D) who knows how to use this powerful undocumented API.
Now, now. There are many people who use CFRunLoop, and the real
authority on this topic is Chris Kane. Also, for those who have used
NSRunLoop--which has been in existence and documented for
years--CFRunLoop should seem quite familiar.
Here is a summary covering much of what we said on the topic at the last
WWDC. We do sometimes answer specific questions on this list, as well.
Cocoa applications and Carbon Event-based applications have one notable
thing in common: they are both event-driven. That is, they are
normally waiting for something to happen, after which control is handed
to application code to deal with whatever it was, and the application
goes back to waiting. They use a common mechanism for this: the run
loop. The run loop is a means of waiting for a variety of occurrences
at once, conveniently and efficiently, without polling or
multithreading. These occurrences can be such things as the arrival of
a Mach message, or the arrival of a network packet, or just the arrival
of some specific time, or more abstract occurrences based on these
primitives.
There is a single underlying run loop object for each thread (called the
"current" run loop for that thread), and although there are a number of
APIs for dealing with it, they all deal with the same underlying thing,
and hence any or all of them can be used together. For example,
although NSRunLoop and CFRunLoop are not toll-free bridged--meaning that
you cannot sent NSRunLoop methods to a CFRunLoop or use CFRunLoop
functions on an NSRunLoop--they still both add their sources to the same
underlying run loop. You should deal with the API level appropriate to
your needs, preferably at the highest suitable level. The primary
reason for working with CFRunLoop directly rather than with higher-level
APIs would be because you wished to make use of CF-based run loop
sources, e.g. CFMessagePort, CFMachPort, CFSocket, CFRunLoopTimer.
If you are working within a Cocoa or Carbon Event-based application, you
usually will not need to run the run loop yourself, at least on the main
thread, because the frameworks will be doing it for you as part of their
normal event handling. In this case what you would wish to do is to
create sources and add them to the run loop for the main thread; then
you will get a notification in the form of a callback when the thing you
are waiting for happens, on the main thread, within the main event
loop. If you are not within the context of a Cocoa or Carbon
Event-based application, or if you are working on another thread, then
you can still use that thread's run loop, but you would need to run it
yourself--that is, tell it to start waiting for things to happen.
For example, if you are working with Mach messages or BSD sockets, and
you wish to be notified when data arrives, without having to create a
separate thread to wait for it, you can create a CFMachPort or a
CFSocket, get a run loop source from it, and add it to the run loop. If
you want a high-performance local IPC mechanism, but don't want to deal
with the complexities of Mach messages (and don't need the full
flexibility of Mach messaging) then you can use CFMessagePort instead.
Again, the receiving CFMessagePort will provide a run loop source, which
you can add to the run loop, so that you will be notified with a
callback when messages arrive.
The simplest thing you can wait for on a run loop is just the arrival of
a specific time. There are higher-level APIs for this, but it can also
be done at the CF level with a CFRunLoopTimer. The way this works is
that each timer has a specific time, or a sequence of repeating times,
at which it is supposed to fire--i.e., generate a callback. When the
run loop is waiting, it checks to see whether the time has arrived for
any timer attached to it, and if so that timer's callback is sent. Note
that this only happens while the run loop is waiting; this is not a
real-time mechanism, and if you spend significant amounts of time
processing rather than waiting in the run loop, or if your application
is not scheduled for some time, timer firings will be delayed.
Run loops also have something called modes. It may not be desirable to
wait for every class of occurrences at all times. For example, you may
not wish to have a specific timer fire while the application is tracking
mouse moves. When a source is added to a run loop, it is added to a
specific mode or set of modes, or to the set of so-called "common"
modes. When the run loop is run, it is run with a particular mode, and
only those sources added for that mode are active. For Cocoa
applications, the common modes are: the default mode, used most of the
time; the event tracking mode, used when tracking mouse moves; and the
modal panel mode, used when a modal panel is up.
This is a general conceptual overview; I can probably be more specific
if there are more specific questions about exactly how to add a source
to a run loop.
Douglas Davidson