{"id":609,"date":"2010-02-07T22:59:31","date_gmt":"2010-02-08T05:59:31","guid":{"rendered":"http:\/\/thesmithfam.org\/blog\/?p=609"},"modified":"2019-08-12T07:15:31","modified_gmt":"2019-08-12T13:15:31","slug":"talking-to-qt-threads","status":"publish","type":"post","link":"https:\/\/thesmithfam.org\/blog\/2010\/02\/07\/talking-to-qt-threads\/","title":{"rendered":"Talking to Qt Threads"},"content":{"rendered":"<p>I wrote about <a href=\"https:\/\/thesmithfam.org\/blog\/2009\/09\/30\/lock-free-multi-threading-in-qt\/\">multi-threading in Qt<\/a> a while back, and how to use <b>QThread<\/b> to wrap a blocking function call &#8220;lock free&#8221;. Today we&#8217;ll talk about how to pass data into your thread. This approach can be used, for example, to tell your <b>QThread<\/b> to stop.<\/p>\n<style>\npre { font-size: 10pt; border: 2px solid #016; padding: 5px; color: white; background: #333; }\n<\/style>\n<p>There are two ways to use <b>QThread<\/b>, with and without an event loop, and the preferred method for talking to a <b>QThread<\/b> depends on which of them you use.<\/p>\n<p><b>Way 1: Without an event loop<\/b><\/p>\n<p>When you&#8217;re not using an event loop, the thread&#8217;s <b>run()<\/b> method often looks like this:<\/p>\n<pre>\r\nvoid MyThread::run()\r\n{\r\n    forever\r\n    {\r\n        \/\/ Do some stuff\r\n    }\r\n}\r\n<\/pre>\n<p>Since this method does not use an event loop, there is no way to deliver a signal to your thread. So if you want to pass data into the thread, you have to use a good old fashioned mutex. Let&#8217;s look at an example showing you how to <b>stop<\/b> your thread:<\/p>\n<pre>\r\nvoid MyThread::run()\r\n{\r\n    forever\r\n    {\r\n        {\r\n            \/\/ \"mutex\" and \"stopRequested\" are member\r\n            \/\/ variables of MyThread:\r\n            QMutexLocker locker(&mutex);\r\n            if(stopRequested)\r\n                return;\r\n        }\r\n        \r\n        \/\/ Do some stuff\r\n    }\r\n}\r\n\r\nvoid MyThread::stop()\r\n{\r\n    QMutexLocker locker(&mutex);\r\n    stopRequested = true;\r\n}\r\n<\/pre>\n<p>In this case, we have to check the <b>stopRequested<\/b> variable in a timely manner in our thread&#8217;s <b>run()<\/b> method. The longer you run between checks, the longer it will take your thread to actually stop.<\/p>\n<p>Outside observers can use the <b>finished()<\/b> signal to know when your thread is actually done. So if you are in a QMainWindow, for example, and a <b>closeEvent()<\/b> happens, you can ignore the event, call <b>MyThread::stop()<\/b>, and then when the <b>QThread::finished()<\/b> signal arrives, you can actually close the window.<\/p>\n<p>The downside is that the <b>stop()<\/b> call will actually block while it tries to acquire the <b>mutex<\/b>. Given the way this code is written, the blocking will probably be very short, but hey, I hate blocking. Let&#8217;s see if we can dig up a better way to do this.<\/p>\n<p><b>Way 2: With an event loop<\/b><\/p>\n<p>If you have an event loop, you can use Qt&#8217;s meta-objects to talk to your thread. Let&#8217;s look at the same example as before, only this time with no locking or blocking.<\/p>\n<pre>\r\nvoid MyThread::MyThread()\r\n{\r\n    moveToThread(this);\r\n}\r\n\r\nvoid MyThread::run()\r\n{\r\n    QTimer *timer = new QTimer();\r\n    connect(timer, SIGNAL(timeout()),\r\n        this, SLOT(doSomething()));\r\n    timer->start(0);\r\n\r\n    exec(); \/\/ starts the event loop, and doesn't\r\n            \/\/ return until it is told to quit()\r\n}\r\n\r\nvoid MyThread::stop()\r\n{\r\n    if(currentThread() != this)\r\n    {\r\n        \/\/ The caller is running in a\r\n        \/\/ different thread, so use Qt to\r\n        \/\/ call stop() later, on our own thread:\r\n        QMetaObject::invokeMethod(this, \"stop\",\r\n                        Qt::QueuedConnection);\r\n    }\r\n    else\r\n    {\r\n        \/\/ Now the call has arrived from our\r\n        \/\/ own thread, yay! We can safely\r\n        \/\/ shut down our event loop.\r\n        quit();\r\n    }\r\n}\r\n<\/pre>\n<p>Look mom! No locks! Now we have killed our thread, safely and gracefully. There is no chance of blocking, and we learned something about QMetaObject.<\/p>\n<p>A couple items to note:<\/p>\n<ul>\n<li>The <b>doSomething()<\/b> method is left as an exercise for the reader, but be careful about the <b>QTimer<\/b> interval. I used <b>0<\/b>, which means it will be firing almost constantly.<\/li>\n<li>The <b>stop()<\/b> method must be a <b>slot<\/b> in MyThread (and not just a regular method) or else <b>invokeMethod()<\/b> will return false and not actually re-invoke <b>stop()<\/b> for you.<\/li>\n<li>You <b>can<\/b> pass arguments to your thread this way, but it requires a bit more fun with <a href=\"http:\/\/doc.trolltech.com\/4.6\/qmetaobject.html\">QMetaObject::invokeMethod()<\/a>.<\/li>\n<li>You can reduce this whole thing to a magical macro that you could put at the top of your stop() method, saving you from having to write <b>if(currentThread() == this)<\/b> at the top of every method. Hint: use the __FUNCTION__ macro.<\/li>\n<li>To run this example code, you&#8217;ll need to <b>#include<\/b> these files: QThread, QTimer, QMetaObject, QMutexLocker, and QMutex<\/li>\n<li>To call <b>quit()<\/b>, it may not actually be necessary to be running on the same <b>QThread<\/b> (it works for me without the QMetaObject), but this will be required when you start passing in data to your thread. Without it, your program could do unpredictable naughty things. I can&#8217;t find anything in the docs about whether <b>quit()<\/b> is thread safe.\n<\/li>\n<\/ul>\n<p>I&#8217;ve found this <b>QMetaObject<\/b> approach the most effective and easiest way to pass data to <b>QThreads<\/b> safely, without blocking and without locks.<\/p>\n<p>Happy threading!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wrote about multi-threading in Qt a while back, and how to use QThread to wrap a blocking function call &#8220;lock free&#8221;. Today we&#8217;ll talk about how to pass data into your thread. This approach can be used, for example, to tell your QThread to stop. There are two ways to use QThread, with and [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-609","post","type-post","status-publish","format-standard","hentry","category-code-and-cruft"],"_links":{"self":[{"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/posts\/609","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/comments?post=609"}],"version-history":[{"count":27,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/posts\/609\/revisions"}],"predecessor-version":[{"id":1525,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/posts\/609\/revisions\/1525"}],"wp:attachment":[{"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/media?parent=609"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/categories?post=609"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/tags?post=609"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}