Skip to content

Instantly share code, notes, and snippets.

@TheWaWaR
Last active December 15, 2015 23:49
Show Gist options
  • Save TheWaWaR/5343424 to your computer and use it in GitHub Desktop.
Save TheWaWaR/5343424 to your computer and use it in GitHub Desktop.
<Qt Threading Basics> Document Reading Note

What are threads

Blabla... thread is tiny process that share the memory.

  • Thread can run on multicore CPUs. But how about The C10K problem?

GUI Thread and Worker Thread

  • Qt GUI must run in "main thread"

Simultaneous Access to Data

  • Simultaneous access an shared object will be faster that communicate in process, but it's also dangerous.
  • Some cases will cause danger
    • static members
    • singletons
    • global data
  • How to use thread safely thread safe and reentrant

Using Threads

We use thread to make processing faster and keep the GUI thread unblock

When to Use Alternatives to Threads

Threads are dangerous. When we want to use thread at a time we'd better consider some alternatives.

  1. QEventLoop::processEvents() Just event loop, this solution doesn't scale well, because the call to processEvents() unpredictable.
  2. QTimer For short task it'll conveniently, but time consuming task'll block the GUI thread.
  3. [Network stuff]
  • QSocketNotifier
  • QNetworkAccessManager
  • QIODevice::readyRead()
  1. QConcurrent Functional way to perform an computation. If use the run() method for the target function it'll run in a separate Thread from the default QThreadPool.

Which Qt Thread Technology Should You Use?

The Qt Thread Scenes

  • One call : Just run a method and quit. [Solutions]
    1. QtConcurrent::run()
    2. Derive a class from QRunnable and run it in the global thread poll with QThreadPool::globalInstance()->start()
    3. Derive a class from QThread, reimplement the QThread::run() method and use QThread::start() to run it.
  • One call : Perform on all items of a container(such as produce thumbnails from images) [Solutions]
    1. QtConcurrent::map()
    2. QtConcurrent::filter()
    3. Other QtConcurrent methods...
  • One call : Long running operation, during the course status information should be sent to the GUI thread. [Solutions]
    1. Use QThread, reimplement run and emit signals as needed, then connect the signals to the GUI thread's slots.
  • Permanent : Need to communicate to and from the worker thread. [Solutions]
    1. Derive a class from QObject and implement the necessary slots and signals, move the object to a thread with a running event loop and communicate with the object over queued signal/slot connections
  • Permanent : Although the class is called QSocketNotifier, it is normally used for other types of devices than sockets. QTcpSocket and QUdpSocket provide notification through signals, so there is normally no need to use a QSocketNotifier on them. [Solutions]
    1. Same as above but also use a timer in worker thread to implement polling. To do this, you'd better use QSocketNotifier

Qt Thread Basics

The easy way to use QThread:

  1. Derive a class from QThread, let's call it SomeThread
  2. Implement the run() method
  3. Create an instance of SomeThread, then call it's start() method. Note: Exiting the program when another thread is still busy is a programming error, therefore, we need to call thread's wait() method before exiting.

QObject and Threads

  • The thread where the QObject lives should have an event loop to deliver the event. Call exec() method to start an event loop.

  • On Linux, Valgrind and Helgrind can help detect threading errors.

  • The anatomy of QThread:

    • Before run() is executed, QThread lives in the old thread. run() started, mean new thread started.
    • Most QThread methods are the thread's control interface and are meant to be called from the old thread.....
    • The parameter variables pass to the sub thread should not touch them from main thread anymore.
  • A QObject's parent must always be in the same thread. We must be careful when we alloc an QObject in run() method.

    void HelloThread::run()
    {
         QObject *object1 = new QObject(this);  //error, parent must be in the same thread
         QObject object2;  // OK
         QSharedPointer <QObject> object3(new QObject); // OK
    }

    QObject *object1 = new QObject(this); is error, because this object is in main thread.

Using a Mutex to Protect the Integrity of Data

  • Between lock() and unlock() if an exception occurs it'll never reach the unlock() method then all related threads'll frozen. We use QMutexLocker locker(&mutex) to prevent this problems like this.
  • Most Qt methods aren't thread-safe.
  • Mutexes will introduce deadlock problems.

Using the Event Loop to Prevent Data Corruption

Every thread may have it's own event loop. A safe way to calling a slot in another thread is by placing that call in another thread's event loop. So how is it possible to put a method invocation in an event loop? [Solutions]

  1. Make queued signal/slot connections
  2. Post an event with QCoreApplication::postEvent().

Dealing with Asynchronous Execution

How can we obtain a worker thread's result? In many cases, a blocking wait isn't acceptable. [Solutions] The same as above --

Examples

You'll know:

  • How to communicate with a running thread.
  • How a QObject can be placed in another thread, providing service to the main thread.

Example 1: Using the Thread Pool

We use thread pool beacuse creating and destroying threads frequently can be expensive.

[QThread vs QRunnable] :

  • QThread is low-level threading primitive to create and handle threads.

  • QRunnable is high-level concept (command pattern) and is thread independent. QRunnable objects can be executed in another thread but doesn't have to be.

     // hellothreadpool/main.cpp
     class Work : public QRunnable
     {
     public:
         void run()
         {
             qDebug() << "Hello from thread " << QThread::currentThread();
         }
     };
    
     int main(int argc, char *argv[])
     {
         QCoreApplication app(argc, argv);
         Work work;
         work.setAutoDelete(false);
         QThreadPool *threadPool = QThreadPool::globalInstance();
         threadPool->start(&work);
         qDebug() << "hello from GUI thread " << QThread::currentThread();
         threadPool->waitForDone();
         return 0;
     }

work.setAutoDelete(false); : work thread not destroyed after it have finished running.

Example 2: Using QtConcurrent

Already learnt it, see the sample code in project AllForTest

Example 3: Clock

Shows how to communicate from worker thread to GUI thread. [easy]

  • Use signal/slot to communicate from worker to GUI thread

    QObject::connect(thread, SIGNAL(signalInThread()), widget, SLOT(slotInGUIThread()), Qt::QueuedConnection)
  • Use QTimer to receive time change event from system

Example 4: A Permanent Thread

Show how to communicate from GUI thread to worker thread (send task to worker thread).

  1. Derive a class from QThread (SomeThread)
  2. Derive a class from QObject define some methods do the work(WorkerObject)
  3. Create a SomeThread object(thread) and WorkerObject object(worker), move worker to thread by worker->moveToThread(thread)
  4. In GUI thread, send task to worker thread by:
    • QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection)

Digging Deeper

  1. Video : Training Day at Qt Developer Days 2009
  2. Document: Thread Support in Qt
  3. Examples : QThread and QtConcurrent
  4. Book : Advanced Qt Programming by <Mark Summerfield, Prentice Hall>

[Meta infomation]

  • Threading Basics
  • Created at: [2013-04-07 15:49]
  • Finished at: [2013-04-09 14:32]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment