Using threads isn't possible on all platforms. This is why aRts was originally written without using threading at all. For almost all problems, for each threaded solution to the problem, there is a non-threaded solution that does the same.
For instance, instead of putting audio output in a seperate thread, and make it blocking, aRts uses non-blocking audio output, and figures out when to write the next chunk of data using select().
However, aRts (in very recent versions) at least provides support for people who do want to implement their objects using threads. For instance, if you already have code for an mp3 player, and the code expects the mp3 decoder to run in a seperate thread, it's usally the easiest thing to do to keep this design.
The aRts/MCOP implementation is built along sharing state between seperate objects in obvious and non-obvious ways. A small list of shared state includes:
All of the above objects don't expect to be used concurrently (i.e. called from seperate threads at the same time). Generally there are two ways of solving this:
aRts follows the first approach: you will need a lock whenever you talk to any of these objects. The second approach is harder to do. A hack which tries to achieve this is available at http://space.twc.de/~stefan/kde/download/arts-mt.tar.gz, but for the current point in time, a minimalistic approach will probably work better, and cause less problems with existing applications.
You can get/release the lock with the two functions:
Generally, you don't need to acquire the lock (and you shouldn't try to do so), if it is already held. A list of conditions when this is the case is:
There are also some exceptions of functions. which you can only call in the main thread, and for that reason you will never need a lock to call them:
But that is it. For everything else that is somehow related to aRts, you will need to get the lock, and release it again when done. Always. Here is a simple example:
class SuspendTimeThread : Arts::Thread { public: void run() { /* * you need this lock because: * - constructing a reference needs a lock (as global: will go to * the object manager, which might in turn need the GlobalComm * object to look up where to connect to) * - assigning a smartwrapper needs a lock * - constructing an object from reference needs a lock (because it * might need to connect a server) */ Arts::Dispatcher::lock(); Arts::SoundServer server = Arts::Reference("global:Arts_SoundServer"); Arts::Dispatcher::unlock(); for(;;) { /* * you need a lock here, because * - dereferencing a smartwrapper needs a lock (because it might * do lazy creation) * - doing an MCOP invocation needs a lock */ Arts::Dispatcher::lock(); long seconds = server.secondsUntilSuspend(); Arts::Dispatcher::unlock(); printf("seconds until suspend = %d",seconds); sleep(1); } } }
The following threading related classes are currently available:
Arts::Thread - which encapsulates a thread.
Arts::Mutex - which encapsulates a mutex.
Arts::ThreadCondition - which provides support to wake up threads which are waiting for a certain condition to become true.
Arts::SystemThreads - which encapsulates the operating system threading layer (which offers a few helpful functions to application programmers).
See the links for documentation.