Home | All Classes | Main Classes | Annotated | Grouped Classes | Functions

Thread Support in TQt

Introduction

TQt provides thread support in the form of basic platform-independent threading classes, a thread-safe way of posting events, and a global TQt library lock that allows you to call TQt methods from different threads.

This document is intended for an audience that has knowledge of, and experience with, multithreaded applications. If you are new to threading see our Recommended Reading list.

Enabling Thread Support

When TQt is installed on Windows, thread support is an option on some compilers.

On Mac OS X and Unix, thread support is enabled by default on platforms which support it. It might be disabled by adding the -no-thread option when running the configure script. Due to historical reasons on Unix platforms, installation will create a separate library, libtqt-mt and hence threaded programs must be linked against this library (with -ltqt-mt) rather than the standard libtqt library.

The Thread Classes

These classes are built into the TQt library when thread support is enabled:

Important Definitions

When using TQt in a multithreaded program, it is important to understand the definition of the terms reentrant and thread-safe:

Note that TQt provides both implictly and explicitly shared classes. For more information, see the Threads and Shared Data section.

Most C++ member functions are inherently reentrant, since they only reference class member data. Any thread can call such a member function on an instance, as long as no other thread is calling a member function on the same instance. For example, given the class Number below:

    class Number
    {
    public:
        inline Number( int n ) : num( n ) { }

        inline int number() const { return num; }
        inline void setNumber( int n ) { num = n; }

    private:
        int num;
    };

The methods Number::number() and Number::setNumber() are reentrant, since they only reference unique data. Only one thread at a time can call member functions on each instance of Number. However, multiple threads can call member functions on separate instances of Number.

Thread-safe functions usually use a mutex (e.g a TQMutex) to serialize access to shared data. Because of this, thread-safe functions are usually slower than reentrant functions, because of the extra overhead of locking and unlocking the mutex. For example, given the class Counter below:

    class Counter
    {
    public:
        inline Counter()  { ++instances; }
        inline ~Counter() { --instances; }

    private:
        static int instances;
    };

Since the modifications of the static instances integer are not serialized, this class is not thread-safe. So make it threadsafe, a mutex must be used:

    class Counter
    {
    public:
        inline Counter()
        {
            mutex.lock();
            ++instances;
            mutex.unlock();
        }

        ...
    private:
        static TQMutex mutex;
        static int instances;
    };

Thread-safe Event Posting

In TQt, one thread is always the GUI or event thread. This is the thread that creates a TQApplication object and calls TQApplication::exec(). This is also the initial thread that calls main() at program start. This thread is the only thread that is allowed to perform GUI operations, including generating and receiving events from the window system. TQt does not support creating TQApplication and running the event loop (with TQApplication::exec()) in a secondary thread. You must create the TQApplication object and call TQApplication::exec() from the main() function in your program.

Threads that wish to display data in a widget cannot modify the widget directly, so they must post an event to the widget using TQApplication::postEvent(). The event will be delivered later on by the GUI thread.

Normally, the programmer would like to include some information in the event sent to the widget. See the documentation for TQCustomEvent for more information on user-defined events.

Threads and TQObject subclasses

The TQObject class itself is reentrant. However, certain rules apply when creating and using TQObjects in a thread that is not the GUI thread.

  1. None of the TQObject based classes included in the TQt library are reentrant. This includes all widgets (e.g. TQWidget and subclasses), OS kernel classes (e.g. TQProcess, TQAccel, TQTimer), and all networking classes (e.g. TQSocket, TQDns).

  2. TQObject and all of its subclasses are not thread-safe. This includes the entire event delivery system. It is important to remember that the GUI thread may be delivering events to your TQObject subclass while you are accessing the object from another thread. If you are using TQObject in a thread that is not the GUI thread, and you are handling events sent to this object, you must protect all access to your data with a mutex; otherwise you may experience crashes or other undesired behavior.

  3. As a corollary to the above, deleting a TQObject while pending events are waiting to be delivered can cause a crash. You must not delete the TQObject directly from a thread that is not the GUI thread. Use the TQObject::deleteLater() method instead, which will cause the event loop to delete the object after all pending events have been delivered to the object.

The TQt Library Mutex

TQApplication includes a mutex that is used to protect access to window system functions. This mutex is locked while the event loop is running (e.g. during event delivery) and unlocked when the eventloop goes to sleep. Note: The TQt event loop is recursive, and the library mutex is not unlocked when re-entering the event loop (e.g. when executing a modal dialog with TQDialog::exec()).

If another thread locks the TQt library mutex, then the event loop will stop processing events, and the locking thread may do simple GUI operations. Operations such as creating a TQPainter and drawing a line are examples of simple GUI operations:

    ...
    tqApp->lock();

    TQPainter p;
    p.begin( mywidget );
    p.setPen( TQColor( "red" ) );
    p.drawLine( 0,0,100,100 );
    p.end();

    tqApp->unlock();
    ...

Any operations that generate events must not be called by any thread other than the GUI thread. Examples of such operations are:

Events generated by these operations will be lost on some platforms.

Threads and Signals and Slots

The Signals and Slots mechanism can be used in separate threads, as long as the rules for TQObject based classes are followed. The Signals and Slots mechanism is synchronous: when a signal is emitted, all slots are called immediately. The slots are executed in the thread context that emitted the signal.

Warning: Slots that generate window system events or use window system functions must not be connected to a signal that is emitted from a thread that is not the GUI thread. See the TQt Library Mutex section above for more details.

Threads and Shared Data

TQt provides many implicitly shared and explicitly shared classes. In a multithreaded program, multiple instances of a shared class can reference shared data, which is dangerous if one or more threads attempt to modify the data. TQt provides the TQDeepCopy class, which ensures that shared classes reference unique data.

See the description of implicit sharing for more information.

Threads and the SQL Module

A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread is not supported.

In addition, the third party libraries used by the TQSqlDrivers can impose further restrictions on using the SQL Module in a multithreaded program. Consult the manual of your database client for more information.

Caveats

Some things to watch out for when programming with threads:

Recommended Reading


Copyright © 2007 TrolltechTrademarks
TQt 3.3.8