Set Thread Priority In QtConcurrent

From Qt Wiki
Revision as of 10:35, 24 February 2015 by Maintenance script (talk | contribs)
Jump to navigation Jump to search

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 &lt;QtCore/QtGlobal&amp;gt;<br />#include &lt;QtCore/QAtomicInt&amp;gt;<br />#include &lt;QtCore/QMutex&amp;gt;<br />#include &lt;QtCore/QWaitCondition&amp;gt;<br />#include &lt;QtCore/QThreadStorage&amp;gt;<br />#include &lt;QtCore/QThread&amp;gt;
<br />namespace CallOnce {<br /> enum ECallOnce {<br /> CO_Request,<br /> CO_InProgress,<br /> CO_Finished<br /> };
<br /> Q_GLOBAL_STATIC(QThreadStorage&amp;lt;QAtomicInt*&gt;, once_flag)<br />}
<br />template &lt;class Function&amp;gt;<br /> inline static void qCallOnce(Function func, QBasicAtomicInt&amp;amp; flag)<br />{<br /> using namespace CallOnce;<br /> int protectFlag = flag.fetchAndStoreAcquire((int)flag);<br /> if (protectFlag  CO_Finished)
        return;
    if (protectFlag  CO_Request &amp;&amp; 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 &lt;class Function&amp;gt;<br /> inline static void qCallOncePerThread(Function func)<br />{<br /> using namespace CallOnce;<br /> if (!once_flag()<s>&gt;hasLocalData()) {<br /> once_flag()</s>&gt;setLocalData(new QAtomicInt(CallOnce::CO_Request));<br /> qCallOnce(func, *once_flag()-&gt;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 &lt;QtCore/QtGlobal&amp;gt;<br />#include &lt;QtCore/QtDebug&amp;gt;
<br />#include &lt;QtCore/QTimer&amp;gt;
<br />#include &lt;QtCore/QTime&amp;gt;
<br />#include &lt;QtCore/QVector&amp;gt;<br />#include &lt;QtCore/QThread&amp;gt;<br />#include &lt;QtCore/QtConcurrentMap&amp;gt;<br />#include &lt;QtCore/QtConcurrentFilter&amp;gt;<br />#include &lt;QtCore/QCoreApplication&amp;gt;
<br />#include &lt;algorithm&amp;gt;
<br />#include &quot;call_once.h&amp;quot;
<br />enum {Max = 100};
<br />struct run_once<br />{<br /> void operator()()<br /> {<br /> qDebug() &lt;&lt; &quot;Functor: This only once&quot;;<br /> }<br />};
<br />void func_run_once()<br />{<br /> qDebug() &lt;&lt; &quot;Function: This only once&quot;;<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-&gt;setPriority(m_priority);<br /> }<br /> QThread::Priority m_priority;<br />};
<br />void setLowestPriorityFunction()<br />{<br /> QThread* thread = QThread::currentThread();<br /> thread-&gt;setPriority(QThread::LowestPriority);
<br /> qDebug(&quot;Current thread %x. Thread set to Lowest priority&amp;quot;,<br /> (quintptr)thread);<br />}
<br />void setHighestPriorityFunction()<br />{<br /> QThread* thread = QThread::currentThread();<br /> thread-&gt;setPriority(QThread::HighestPriority);
<br /> qDebug(&quot;Current thread x. Thread set to Highest priority&amp;quot;,<br /> (quintptr)thread);<br />}
<br />int calculate(const int&amp;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;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 &lt; 1000 * 1000 * 100;''+i)<br /> qCallOnce(run_once(), testflag);<br /> qDebug(&quot;%d ms&amp;quot;, t.elapsed());

QVector&amp;lt;int&amp;gt; ints;

std::generate_n(std::back_inserter(ints),<br /> (int)Max, inc_functor());

// Test qCallOnce<br /> {<br /> QVector&amp;lt;int&amp;gt; results = QtConcurrent::blockingMapped(ints, calculate);<br /> qDebug() &lt;&lt; results;<br /> }

// Test qCallOncePerThread<br /> {<br /> QtConcurrent::blockingFilter(ints, parityFilter);<br /> qDebug() &lt;&lt; ints;<br /> }

return 0;<br />}

"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