Set Thread Priority In QtConcurrent: Difference between revisions
No edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
h1. How to set thread priority for concurrent threads (QtConcurrent) | |||
QThread class have method setPriority(), but QtConcurrent | QThread class have method setPriority(), but QtConcurrent doesn't. So i write own implementation with using call_once function. But current C++ standard does not have this function, it's only in C+''0x and BOOST. After some googling i found few implementations and select one. QAtomicInt not ideal class for create thread-safe code and i had to use few undocumented features like QBasicAtomicInt, because it POD type and can be initialized statically inside executable file before all potential parallel initializations inside concurrent threads. | ||
<br /><code><br />#ifndef CALL_ONCE_H<br />#define CALL_ONCE_H | |||
<br />#include <QtCore/QtGlobal&gt;<br />#include <QtCore/QAtomicInt&gt;<br />#include <QtCore/QMutex&gt;<br />#include <QtCore/QWaitCondition&gt;<br />#include <QtCore/QThreadStorage&gt;<br />#include <QtCore/QThread&gt; | |||
<br />namespace CallOnce {<br /> enum ECallOnce {<br /> CO_Request,<br /> CO_InProgress,<br /> CO_Finished<br /> }; | |||
<br /> Q_GLOBAL_STATIC(QThreadStorage&lt;QAtomicInt*>, once_flag)<br />} | |||
<br />template <class Function&gt;<br /> inline static void qCallOnce(Function func, QBasicAtomicInt&amp; flag)<br />{<br /> using namespace CallOnce;<br /> int protectFlag = flag.fetchAndStoreAcquire((int)flag);<br /> if (protectFlag CO_Finished) | |||
return; | |||
if (protectFlag CO_Request && flag.testAndSetRelaxed(protectFlag,<br /> CO_InProgress)) {<br /> func();<br /> flag.fetchAndStoreRelease(CO_Finished);<br /> }<br /> else {<br /> do {<br /> QThread::yieldCurrentThread();<br /> }<br /> while (!flag.testAndSetAcquire(CO_Finished, CO_Finished));<br /> }<br />} | |||
<br />template <class Function&gt;<br /> inline static void qCallOncePerThread(Function func)<br />{<br /> using namespace CallOnce;<br /> if (!once_flag()<s>>hasLocalData()) {<br /> once_flag()</s>>setLocalData(new QAtomicInt(CallOnce::CO_Request));<br /> qCallOnce(func, *once_flag()->localData());<br /> }<br />} | |||
<br />#endif // CALL_ONCE_H | |||
<br /></code> | |||
<br />This is example how to use this functions for set thread priority once per thread at run:<br /><code><br />#include <QtCore/QtGlobal&gt;<br />#include <QtCore/QtDebug&gt; | |||
<br />#include <QtCore/QTimer&gt; | |||
<br />#include <QtCore/QTime&gt; | |||
<br />#include <QtCore/QVector&gt;<br />#include <QtCore/QThread&gt;<br />#include <QtCore/QtConcurrentMap&gt;<br />#include <QtCore/QtConcurrentFilter&gt;<br />#include <QtCore/QCoreApplication&gt; | |||
<br />#include <algorithm&gt; | |||
<br />#include "call_once.h&quot; | |||
<br />enum {Max = 100}; | |||
<br />struct run_once<br />{<br /> void operator()()<br /> {<br /> qDebug() << "Functor: This only once…";<br /> }<br />}; | |||
<br />void func_run_once()<br />{<br /> qDebug() << "Function: This only once…";<br />} | |||
<br />struct inc_functor<br />{<br /> inc_functor() : counter(0) {}<br /> inline int operator()() {return counter;}<br /> int counter;<br />}; | |||
<br />struct setPriorityFunctor<br />{<br /> setPriorityFunctor(QThread::Priority priority = QThread::NormalPriority)<br /> : m_priority(priority) {}<br /> inline void operator()()<br /> {<br /> QThread* thread = QThread::currentThread();<br /> thread->setPriority(m_priority);<br /> }<br /> QThread::Priority m_priority;<br />}; | |||
<br />void setLowestPriorityFunction()<br />{<br /> QThread* thread = QThread::currentThread();<br /> thread->setPriority(QThread::LowestPriority); | |||
<br /> qDebug("Current thread %x. Thread set to Lowest priority&quot;,<br /> (quintptr)thread);<br />} | |||
<br />void setHighestPriorityFunction()<br />{<br /> QThread* thread = QThread::currentThread();<br /> thread->setPriority(QThread::HighestPriority); | |||
<br /> qDebug("Current thread x. Thread set to Highest priority&quot;,<br /> (quintptr)thread);<br />} | |||
<br />int calculate(const int&amp; num)<br />{<br />#if 0 // Test once call per thread with function<br /> #if 0 // Set lowest thread priority<br /> qCallOncePerThread(setLowestPriorityFunction);<br /> #else // Set highest thread priority<br /> qCallOncePerThread(setHighestPriorityFunction);<br /> #endif<br />#else // Test once call per thread with functor<br /> #if 0<br /> qCallOncePerThread(setPriorityFunctor(QThread::HighestPriority));<br /> #else<br /> qCallOncePerThread(setPriorityFunctor(QThread::LowestPriority));<br /> #endif<br />#endif | |||
<br /> return ~num;<br />} | |||
<br />static QBasicAtomicInt flag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request); | |||
<br />int parityFilter(const int&amp; num)<br />{<br /> qCallOnce(run_once(), flag); | |||
<br /> return num 2 ? false : true;<br />} | |||
<br />static QBasicAtomicInt testflag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request); | |||
<br />int main(int argc, char* argv[])<br />{<br /> QCoreApplication a(argc, argv); | |||
<br /> QTime t; t.start();<br /> for (int i = 0; i < 1000 * 1000 * 100;''+i)<br /> qCallOnce(run_once(), testflag);<br /> qDebug("%d ms&quot;, t.elapsed()); | |||
QVector&lt;int&gt; ints; | |||
std::generate_n(std::back_inserter(ints),<br /> (int)Max, inc_functor()); | |||
// Test qCallOnce<br /> {<br /> QVector&lt;int&gt; results = QtConcurrent::blockingMapped(ints, calculate);<br /> qDebug() << results;<br /> } | |||
// Test qCallOncePerThread<br /> {<br /> QtConcurrent::blockingFilter(ints, parityFilter);<br /> qDebug() << ints;<br /> } | |||
return 0;<br />} | |||
</code> | |||
"Source&quot;:http://www.forum.crossplatform.ru/index.php?act=attach&amp;type=post&amp;id=1102 | |||
P.S.: this implementation faster than boost::call_once, but slower than std::call_once |
Revision as of 10:35, 24 February 2015
h1. How to set thread priority for concurrent threads (QtConcurrent)
QThread class have method setPriority(), but QtConcurrent doesn't. So i write own implementation with using call_once function. But current C++ standard does not have this function, it's only in C+0x and BOOST. After some googling i found few implementations and select one. QAtomicInt not ideal class for create thread-safe code and i had to use few undocumented features like QBasicAtomicInt, because it POD type and can be initialized statically inside executable file before all potential parallel initializations inside concurrent threads.
<br />#ifndef CALL_ONCE_H<br />#define CALL_ONCE_H
<br />#include <QtCore/QtGlobal&gt;<br />#include <QtCore/QAtomicInt&gt;<br />#include <QtCore/QMutex&gt;<br />#include <QtCore/QWaitCondition&gt;<br />#include <QtCore/QThreadStorage&gt;<br />#include <QtCore/QThread&gt;
<br />namespace CallOnce {<br /> enum ECallOnce {<br /> CO_Request,<br /> CO_InProgress,<br /> CO_Finished<br /> };
<br /> Q_GLOBAL_STATIC(QThreadStorage&lt;QAtomicInt*>, once_flag)<br />}
<br />template <class Function&gt;<br /> inline static void qCallOnce(Function func, QBasicAtomicInt&amp; flag)<br />{<br /> using namespace CallOnce;<br /> int protectFlag = flag.fetchAndStoreAcquire((int)flag);<br /> if (protectFlag CO_Finished)
return;
if (protectFlag CO_Request && flag.testAndSetRelaxed(protectFlag,<br /> CO_InProgress)) {<br /> func();<br /> flag.fetchAndStoreRelease(CO_Finished);<br /> }<br /> else {<br /> do {<br /> QThread::yieldCurrentThread();<br /> }<br /> while (!flag.testAndSetAcquire(CO_Finished, CO_Finished));<br /> }<br />}
<br />template <class Function&gt;<br /> inline static void qCallOncePerThread(Function func)<br />{<br /> using namespace CallOnce;<br /> if (!once_flag()<s>>hasLocalData()) {<br /> once_flag()</s>>setLocalData(new QAtomicInt(CallOnce::CO_Request));<br /> qCallOnce(func, *once_flag()->localData());<br /> }<br />}
<br />#endif // CALL_ONCE_H
<br />
This is example how to use this functions for set thread priority once per thread at run:
<br />#include <QtCore/QtGlobal&gt;<br />#include <QtCore/QtDebug&gt;
<br />#include <QtCore/QTimer&gt;
<br />#include <QtCore/QTime&gt;
<br />#include <QtCore/QVector&gt;<br />#include <QtCore/QThread&gt;<br />#include <QtCore/QtConcurrentMap&gt;<br />#include <QtCore/QtConcurrentFilter&gt;<br />#include <QtCore/QCoreApplication&gt;
<br />#include <algorithm&gt;
<br />#include "call_once.h&quot;
<br />enum {Max = 100};
<br />struct run_once<br />{<br /> void operator()()<br /> {<br /> qDebug() << "Functor: This only once…";<br /> }<br />};
<br />void func_run_once()<br />{<br /> qDebug() << "Function: This only once…";<br />}
<br />struct inc_functor<br />{<br /> inc_functor() : counter(0) {}<br /> inline int operator()() {return counter;}<br /> int counter;<br />};
<br />struct setPriorityFunctor<br />{<br /> setPriorityFunctor(QThread::Priority priority = QThread::NormalPriority)<br /> : m_priority(priority) {}<br /> inline void operator()()<br /> {<br /> QThread* thread = QThread::currentThread();<br /> thread->setPriority(m_priority);<br /> }<br /> QThread::Priority m_priority;<br />};
<br />void setLowestPriorityFunction()<br />{<br /> QThread* thread = QThread::currentThread();<br /> thread->setPriority(QThread::LowestPriority);
<br /> qDebug("Current thread %x. Thread set to Lowest priority&quot;,<br /> (quintptr)thread);<br />}
<br />void setHighestPriorityFunction()<br />{<br /> QThread* thread = QThread::currentThread();<br /> thread->setPriority(QThread::HighestPriority);
<br /> qDebug("Current thread x. Thread set to Highest priority&quot;,<br /> (quintptr)thread);<br />}
<br />int calculate(const int&amp; num)<br />{<br />#if 0 // Test once call per thread with function<br /> #if 0 // Set lowest thread priority<br /> qCallOncePerThread(setLowestPriorityFunction);<br /> #else // Set highest thread priority<br /> qCallOncePerThread(setHighestPriorityFunction);<br /> #endif<br />#else // Test once call per thread with functor<br /> #if 0<br /> qCallOncePerThread(setPriorityFunctor(QThread::HighestPriority));<br /> #else<br /> qCallOncePerThread(setPriorityFunctor(QThread::LowestPriority));<br /> #endif<br />#endif
<br /> return ~num;<br />}
<br />static QBasicAtomicInt flag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request);
<br />int parityFilter(const int&amp; num)<br />{<br /> qCallOnce(run_once(), flag);
<br /> return num 2 ? false : true;<br />}
<br />static QBasicAtomicInt testflag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request);
<br />int main(int argc, char* argv[])<br />{<br /> QCoreApplication a(argc, argv);
<br /> QTime t; t.start();<br /> for (int i = 0; i < 1000 * 1000 * 100;''+i)<br /> qCallOnce(run_once(), testflag);<br /> qDebug("%d ms&quot;, t.elapsed());
QVector&lt;int&gt; ints;
std::generate_n(std::back_inserter(ints),<br /> (int)Max, inc_functor());
// Test qCallOnce<br /> {<br /> QVector&lt;int&gt; results = QtConcurrent::blockingMapped(ints, calculate);<br /> qDebug() << results;<br /> }
// Test qCallOncePerThread<br /> {<br /> QtConcurrent::blockingFilter(ints, parityFilter);<br /> qDebug() << ints;<br /> }
return 0;<br />}
"Source":http://www.forum.crossplatform.ru/index.php?act=attach&type=post&id=1102
P.S.: this implementation faster than boost::call_once, but slower than std::call_once