qt multi threads
DESCRIPTION
How to write multi threaded applications using Qt: In the slides you'll learn about 3 alternatives, all of which allow running tasks simultaneously in Qt applications, and understand the use cases leading to choosing each.TRANSCRIPT
![Page 1: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/1.jpg)
Qt ConcurrencyYnon Perek
![Page 2: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/2.jpg)
Agenda
• Doing things simultaneously
• Using the event loop
• Using threads
• Using QtConcurrent algorithms
![Page 3: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/3.jpg)
The Event Loop
MainLoop
HandlerHandlerHandler
event 1
![Page 4: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/4.jpg)
You’re Already Doing It
• Network code runs in parallel
• Timers
![Page 5: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/5.jpg)
Unfortunately …
• DB queries block
• Disk operations block
• CPU operations block
![Page 6: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/6.jpg)
Latency Is The Enemy
![Page 7: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/7.jpg)
What We Need
• Run something “in the background”
• A single task
• A worker thread
• A full algorithm
• Another application
![Page 8: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/8.jpg)
Single TaskQThread QThreadPool QRunnable Thread Synchronization
![Page 9: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/9.jpg)
Threads Theory
• Define tasks by extending QRunnable
• Use QThreadsPool to run them
![Page 10: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/10.jpg)
Demo Runnable
class MyTask : public QRunnable { virtual void run() { for ( int i=0; i < 10; i++ ) { qDebug() << "[" << QThread::currentThreadId() << "]" << " " << i; } } };
![Page 11: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/11.jpg)
Using The Thread Pool
QCoreApplication a(argc, argv); MyTask *t1 = new MyTask;
QThreadPool p; p.start(t1);
p.waitForDone();
![Page 12: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/12.jpg)
Thread Pool Notes
• start() takes ownership of the runnable. It will be deleted when done
• Number of threads matches number of CPU cores
• waitForDone() stops the event loop. Be careful with that one
![Page 13: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/13.jpg)
Yielding
• If you feel your thread has worked hard enough, rest with:QThread::yieldCurrentThread();
![Page 14: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/14.jpg)
Sharing
• Cool in real life
• Uncool for threads
![Page 15: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/15.jpg)
Sharing Problems
• Shared resources can be manipulated from other threads
• Even when you’re in the middle
![Page 16: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/16.jpg)
Sharing Problems
class Counter { public: Counter() { n = 0; }
void increment() { ++n; } void decrement() { --n; } int value() const { return n; }
private: int n; };
Can you use the code below from multiple threads ?
Why ?
![Page 17: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/17.jpg)
Sharing Problems
• Most Qt and C++ code is re-entrant
• It means you can’t access same instance from different threads at the same time
![Page 18: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/18.jpg)
Quiz
• Assume m_text is a QStringList
• Can you use the code from multiple threads ? Why ?
virtual void run() { m_text.append(m_a); for ( int i=0; i < 100; i++ ) { if ( m_text.last() == m_a ) { m_text.append(m_b); } else { m_text.append(m_a); } } }
![Page 19: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/19.jpg)
Thread Safety
• Code is marked thread-safe if it’s ok to use it from multiple threads, on the same instance.
• Thread-safe code manages data access
![Page 20: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/20.jpg)
Other Considerations
• When locking threads, you lose concurrency
• Previous example was better written by:
• Separating the problem to sections
• Solving each section in a thread
![Page 21: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/21.jpg)
Locking Options
• QMutex
• QSemaphore
• QReadWriteLock
• QWaitCondition
![Page 22: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/22.jpg)
QMutex
• Only one thread can “hold” a mutex
• Others wait till done
• Like the java’s synchronized keyword
![Page 23: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/23.jpg)
QMutex Demo
• Consider the two methods on the right
• If called from multiple threads, they’ll break
int number = 6;
void method1() { number *= 5; number /= 4; }
void method2() { number *= 3; number /= 2; }
![Page 24: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/24.jpg)
QMutex Demo
• But the mutex changes everything
• Now method2 has to wait for method1 to finish
QMutex mutex; int number = 6;
void method1() { mutex.lock(); number *= 5; number /= 4; mutex.unlock(); }
void method2() { mutex.lock(); number *= 3; number /= 2; mutex.unlock(); }
![Page 25: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/25.jpg)
Deadlocks
• Forgetting to unlock a mutex creates deadlocks
• Unlocking in a wrong order creates deadlocks
![Page 26: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/26.jpg)
QMutexLocker
With QMutexLocker, you’ll never forget to unlock your mutex
virtual void run() { QMutexLocker l(&mutex); num = 6; m1(); m2(); qDebug() << QThread::currentThreadId() << ") n = " << num; }
![Page 27: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/27.jpg)
Q & A
![Page 28: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/28.jpg)
Lab
• Modify Counter code so it is thread safe
![Page 29: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/29.jpg)
QReadWriteLock
• Multiple reads, single write
• Prevents starvation
![Page 30: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/30.jpg)
Demo• Write a QRunnable class to run the
following code
• Did you segfault ? Good, now fix it
virtual void run() { if ( m_writer ) { m_list << QString::number(qrand()); } else { qDebug() << m_list; } }
![Page 31: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/31.jpg)
QReadWriteLock vs. QMutex
• Use QReadWriteLock when you have many readers and few writers
• For other cases, mutex is sufficient
![Page 32: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/32.jpg)
QSemaphore
• Producer-Consumer problem
• One producer, multiple consumers
![Page 33: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/33.jpg)
QSemaphore
• A general counting semaphore
• Methods:
• acquire(n)
• release(n)
![Page 34: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/34.jpg)
Demo Code
QSemaphore sem(5); // sem.available() == 5
sem.acquire(3); // sem.available() == 2 sem.acquire(2); // sem.available() == 0 sem.release(5); // sem.available() == 5 sem.release(5); // sem.available() == 10
sem.tryAcquire(1); // sem.available() == 9, returns true sem.tryAcquire(250); // sem.available() == 9, returns false
![Page 35: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/35.jpg)
Locking Alternatives
• Locking mechanisms are used to sync with worker threads
• Some alternatives:
• Using QtConcurrent algorithms
![Page 36: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/36.jpg)
Q & A
![Page 37: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/37.jpg)
Qt Style Worker Thread
Main Event Loop
Secondary Event Loop
Signals and Slots
![Page 38: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/38.jpg)
The Code
• Create a worker thread as a normal QObject
• Move it to another thread
• Start the thread’s event loop
MyWorker w; QThread t;
w.moveToThread(&t); t.start();
![Page 39: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/39.jpg)
Why Is It Awesome
• Write code with normal signals and slots
• Make it multi-threaded when needed
• Almost no change
![Page 40: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/40.jpg)
Under The Hood
• QObject::connect uses a message queue to call slots in other threads
![Page 41: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/41.jpg)
Lab
• Write a GUI app that displays an image
• Use QFileDialog to choose image file
• Read image file from a worker thread
![Page 42: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/42.jpg)
Concurrent Algorithms
![Page 43: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/43.jpg)
Concurrent Algorithms
• Algorithms on collections can make use of concurrent primitives
• Qt provides:
• map
• filter
• reduce
![Page 44: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/44.jpg)
Let’s Start With A Demoint main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QList<long> seq; QTime t1,t2;
for (long i=2; i < 100000; i++ ) seq << i;
t1.start(); QtConcurrent::blockingFiltered(seq, isPrime); qDebug("Time elapsed (Multi): %d ms", t1.elapsed());
t2.start(); foreach ( long n, seq ) isPrime(n); qDebug("Time elapsed (Single): %d ms", t2.elapsed());
return 0; }
![Page 45: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/45.jpg)
Results
Time elapsed (Multi): 1433 ms
Time elapsed (Single): 3408 ms
![Page 46: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/46.jpg)
The Good Parts
• Easily implement algorithms on collections
• Avoid common mistakes
• No need to synchronize threads
![Page 47: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/47.jpg)
Other Primitives
• map applies a function to each item in the collection, returning a list of the results
• mappedReduced does map and reduces the result
![Page 48: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/48.jpg)
Other Primitives
• filter applies a function on each item in the collection, returning a list of the “true” ones
• filteredReduced does the same, and also reduces to a single result
![Page 49: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/49.jpg)
Progress Indication
• Algorithms return QFuture object
• Use QFutureWatcher to add signals and slots
![Page 50: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/50.jpg)
Demo Code
QFutureWatcher<long> w; ProgressReporter p;
w.setFuture(QtConcurrent::filtered(seq, isPrime));
QObject::connect(&w, SIGNAL(progressRangeChanged(int,int)), &p, SLOT(progressRangeChanged(int,int))); QObject::connect(&w, SIGNAL(progressValueChanged(int)), &p, SLOT(progressValueChanged(int)));
![Page 51: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/51.jpg)
Progress Notes
• QFutureWatcher is templated to the type of the list
• Progressive filling is possible with:
• resultReadyAt(int)
• resultsReadyAt(int,int)
• Best gain: no latency
![Page 52: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/52.jpg)
Q & A
![Page 53: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/53.jpg)
Concurrency Takeaways
• Use worker threads for IO
• Use QtConcurrent for algorithms
• Latency is the enemy
![Page 54: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/54.jpg)
Lab
• Move our prime number detection code to a GUI app
• User selects range, and the application prints all prime numbers in range
• Try with and without QtConcurrent
![Page 55: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/55.jpg)
Online Resources
• http://qt-project.org/doc/qt-5.0/qtcore/thread-basics.html
• http://www.greenteapress.com/semaphores/
• http://qt-project.org/videos/watch/threaded_programming_with_qt
![Page 56: Qt multi threads](https://reader031.vdocuments.net/reader031/viewer/2022013118/559c1cc21a28ab00158b469b/html5/thumbnails/56.jpg)
Thanks For Listening
• Ynon Perek
• http://ynonperek.com