Threads in aRts
Prev
Next

Threads in aRts

Basics

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 separate 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 separate thread, it's usually the easiest thing to do to keep this design.

The aRts/MCOP implementation is built along sharing state between separate objects in obvious and non-obvious ways. A small list of shared state includes:

  • The Dispatcher object which does MCOP communication.

  • The Reference counting (Smartwrappers).

  • The IOManager which does timer and fd watches.

  • The ObjectManager which creates objects and dynamically loads plugins.

  • The FlowSystem which calls calculateBlock in the appropriate situations.

All of the above objects don't expect to be used concurrently (i.e. called from separate threads at the same time). Generally there are two ways of solving this:

  • Require the caller of any functions on this objects to acquire a lock before using them.

  • Making these objects really threadsafe and/or create per-thread instances of them.

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.

When/how to acquire the lock?

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:

  • You receive a callback from the IOManager (timer or fd).

  • You get call due to some MCOP request.

  • You are called from the NotificationManager.

  • You are called from the FlowSystem (calculateBlock)

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:

  • Constructor/destructor of Dispatcher/IOManager.

  • Dispatcher::run() / IOManager::run()

  • IOManager::processOneEvent()

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);
        }
    }
}

Threading related classes

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.

Prev
Next
Home


Would you like to make a comment or contribute an update to this page?
Send feedback to the KDE Docs Team