Set Thread Priority In QtConcurrent: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 2: Line 2:


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.
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 &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;
<code>
<br />namespace CallOnce {<br /> enum ECallOnce {<br /> CO_Request,<br /> CO_InProgress,<br /> CO_Finished<br /> };
#ifndef CALL_ONCE_H
<br /> Q_GLOBAL_STATIC(QThreadStorage&amp;lt;QAtomicInt*&gt;, once_flag)<br />}
#define CALL_ONCE_H
<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)
 
#include <QtCore/QtGlobal>
#include <QtCore/QAtomicInt>
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>
#include <QtCore/QThreadStorage>
#include <QtCore/QThread>
 
namespace CallOnce {
enum ECallOnce {
CO_Request,
CO_InProgress,
CO_Finished
};
 
Q_GLOBAL_STATIC(QThreadStorage<QAtomicInt*>, once_flag)
}
 
template <class Function>
inline static void qCallOnce(Function func, QBasicAtomicInt&amp;amp; flag)
{
using namespace CallOnce;
int protectFlag = flag.fetchAndStoreAcquire((int)flag);
if (protectFlag  CO_Finished)
         return;
         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 />}
     if (protectFlag  CO_Request &amp;&amp; flag.testAndSetRelaxed(protectFlag,
<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 />}
CO_InProgress)) {
<br />#endif // CALL_ONCE_H
func();
<br /></code>
flag.fetchAndStoreRelease(CO_Finished);
<br />This is example how to use this functions for set thread priority once per thread at run:<br /><code><br />#include &lt;QtCore/QtGlobal&amp;gt;<br />#include &lt;QtCore/QtDebug&amp;gt;
}
<br />#include &lt;QtCore/QTimer&amp;gt;
else {
<br />#include &lt;QtCore/QTime&amp;gt;
do {
<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;
QThread::yieldCurrentThread();
<br />#include &lt;algorithm&amp;gt;
}
<br />#include &quot;call_once.h&amp;quot;
while (!flag.testAndSetAcquire(CO_Finished, CO_Finished));
<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 />};
template <class Function>
<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 />};
inline static void qCallOncePerThread(Function func)
<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 />}
using namespace CallOnce;
<br />void setHighestPriorityFunction()<br />{<br /> QThread* thread = QThread::currentThread();<br /> thread-&gt;setPriority(QThread::HighestPriority);
if (!once_flag()->hasLocalData()) {
<br /> qDebug(&quot;Current thread x. Thread set to Highest priority&amp;quot;,<br /> (quintptr)thread);<br />}
once_flag()->setLocalData(new QAtomicInt(CallOnce::CO_Request));
<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
qCallOnce(func, *once_flag()->localData());
<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 />}
#endif // CALL_ONCE_H
<br />static QBasicAtomicInt testflag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request);
 
<br />int main(int argc, char* argv[])<br />{<br /> QCoreApplication a(argc, argv);
</code>
<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());
 
This is example how to use this functions for set thread priority once per thread at run:
<code>
#include <QtCore/QtGlobal>
#include <QtCore/QtDebug>
 
#include <QtCore/QTimer>
 
#include <QtCore/QTime>
 
#include <QtCore/QVector>
#include <QtCore/QThread>
#include <QtCore/QtConcurrentMap>
#include <QtCore/QtConcurrentFilter>
#include <QtCore/QCoreApplication>
 
#include <algorithm>
 
#include "call_once.h"
 
enum {Max = 100};
 
struct run_once
{
void operator()()
{
qDebug() << "Functor: This only once…";
}
};
 
void func_run_once()
{
qDebug() << "Function: This only once…";
}
 
struct inc_functor
{
inc_functor() : counter(0) {}
inline int operator()() {return counter;}
int counter;
};
 
struct setPriorityFunctor
{
setPriorityFunctor(QThread::Priority priority = QThread::NormalPriority)
: m_priority(priority) {}
inline void operator()()
{
QThread* thread = QThread::currentThread();
thread->setPriority(m_priority);
}
QThread::Priority m_priority;
};
 
void setLowestPriorityFunction()
{
QThread* thread = QThread::currentThread();
thread->setPriority(QThread::LowestPriority);
 
qDebug("Current thread %x. Thread set to Lowest priority",
(quintptr)thread);
}
 
void setHighestPriorityFunction()
{
QThread* thread = QThread::currentThread();
thread->setPriority(QThread::HighestPriority);
 
qDebug("Current thread x. Thread set to Highest priority",
(quintptr)thread);
}
 
int calculate(const int&amp;amp; num)
{
#if 0 // Test once call per thread with function
#if 0 // Set lowest thread priority
qCallOncePerThread(setLowestPriorityFunction);
#else // Set highest thread priority
qCallOncePerThread(setHighestPriorityFunction);
#endif
#else // Test once call per thread with functor
#if 0
qCallOncePerThread(setPriorityFunctor(QThread::HighestPriority));
#else
qCallOncePerThread(setPriorityFunctor(QThread::LowestPriority));
#endif
#endif
 
return ~num;
}
 
static QBasicAtomicInt flag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request);
 
int parityFilter(const int&amp;amp; num)
{
qCallOnce(run_once(), flag);
 
return num 2 ? false : true;
}
 
static QBasicAtomicInt testflag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request);
 
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
 
QTime t; t.start();
for (int i = 0; i < 1000 * 1000 * 100;''+i)
qCallOnce(run_once(), testflag);
qDebug("%d ms", t.elapsed());


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


std::generate_n(std::back_inserter(ints),<br /> (int)Max, inc_functor());
std::generate_n(std::back_inserter(ints),
(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 qCallOnce
{
QVector<int> results = QtConcurrent::blockingMapped(ints, calculate);
qDebug() << results;
}


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


return 0;<br />}
return 0;
}


</code>
</code>


&quot;Source&amp;quot;:http://www.forum.crossplatform.ru/index.php?act=attach&amp;amp;type=post&amp;amp;id=1102
"Source":http://www.forum.crossplatform.ru/index.php?act=attach&amp;amp;type=post&amp;amp;id=1102


P.S.: this implementation faster than boost::call_once, but slower than std::call_once
P.S.: this implementation faster than boost::call_once, but slower than std::call_once

Revision as of 10:55, 25 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.

#ifndef CALL_ONCE_H
#define CALL_ONCE_H

#include <QtCore/QtGlobal>
#include <QtCore/QAtomicInt>
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>
#include <QtCore/QThreadStorage>
#include <QtCore/QThread>

namespace CallOnce {
 enum ECallOnce {
 CO_Request,
 CO_InProgress,
 CO_Finished
 };

 Q_GLOBAL_STATIC(QThreadStorage<QAtomicInt*>, once_flag)
}

template <class Function>
 inline static void qCallOnce(Function func, QBasicAtomicInt&amp;amp; flag)
{
 using namespace CallOnce;
 int protectFlag = flag.fetchAndStoreAcquire((int)flag);
 if (protectFlag  CO_Finished)
        return;
    if (protectFlag  CO_Request &amp;&amp; flag.testAndSetRelaxed(protectFlag,
 CO_InProgress)) {
 func();
 flag.fetchAndStoreRelease(CO_Finished);
 }
 else {
 do {
 QThread::yieldCurrentThread();
 }
 while (!flag.testAndSetAcquire(CO_Finished, CO_Finished));
 }
}

template <class Function>
 inline static void qCallOncePerThread(Function func)
{
 using namespace CallOnce;
 if (!once_flag()->hasLocalData()) {
 once_flag()->setLocalData(new QAtomicInt(CallOnce::CO_Request));
 qCallOnce(func, *once_flag()->localData());
 }
}

#endif // CALL_ONCE_H

This is example how to use this functions for set thread priority once per thread at run:

#include <QtCore/QtGlobal>
#include <QtCore/QtDebug>

#include <QtCore/QTimer>

#include <QtCore/QTime>

#include <QtCore/QVector>
#include <QtCore/QThread>
#include <QtCore/QtConcurrentMap>
#include <QtCore/QtConcurrentFilter>
#include <QtCore/QCoreApplication>

#include <algorithm>

#include "call_once.h"

enum {Max = 100};

struct run_once
{
 void operator()()
 {
 qDebug() << "Functor: This only once…";
 }
};

void func_run_once()
{
 qDebug() << "Function: This only once…";
}

struct inc_functor
{
 inc_functor() : counter(0) {}
 inline int operator()() {return counter;}
 int counter;
};

struct setPriorityFunctor
{
 setPriorityFunctor(QThread::Priority priority = QThread::NormalPriority)
 : m_priority(priority) {}
 inline void operator()()
 {
 QThread* thread = QThread::currentThread();
 thread->setPriority(m_priority);
 }
 QThread::Priority m_priority;
};

void setLowestPriorityFunction()
{
 QThread* thread = QThread::currentThread();
 thread->setPriority(QThread::LowestPriority);

 qDebug("Current thread %x. Thread set to Lowest priority",
 (quintptr)thread);
}

void setHighestPriorityFunction()
{
 QThread* thread = QThread::currentThread();
 thread->setPriority(QThread::HighestPriority);

 qDebug("Current thread x. Thread set to Highest priority",
 (quintptr)thread);
}

int calculate(const int&amp;amp; num)
{
#if 0 // Test once call per thread with function
 #if 0 // Set lowest thread priority
 qCallOncePerThread(setLowestPriorityFunction);
 #else // Set highest thread priority
 qCallOncePerThread(setHighestPriorityFunction);
 #endif
#else // Test once call per thread with functor
 #if 0
 qCallOncePerThread(setPriorityFunctor(QThread::HighestPriority));
 #else
 qCallOncePerThread(setPriorityFunctor(QThread::LowestPriority));
 #endif
#endif

 return ~num;
}

static QBasicAtomicInt flag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request);

int parityFilter(const int&amp;amp; num)
{
 qCallOnce(run_once(), flag);

 return num 2 ? false : true;
}

static QBasicAtomicInt testflag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request);

int main(int argc, char* argv[])
{
 QCoreApplication a(argc, argv);

 QTime t; t.start();
 for (int i = 0; i < 1000 * 1000 * 100;''+i)
 qCallOnce(run_once(), testflag);
 qDebug("%d ms", t.elapsed());

QVector<int> ints;

std::generate_n(std::back_inserter(ints),
 (int)Max, inc_functor());

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

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

return 0;
}

"Source":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