Set Thread Priority In QtConcurrent: Difference between revisions
Jump to navigation
Jump to search
AutoSpider (talk | contribs) (Convert ExpressionEngine links) |
(hmm ? Had a closing code tag but only format properly with extra newline before closing code tag) |
||
(5 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
[[Category:HowTo]] | |||
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. | ||
Line 9: | Line 6: | ||
#define CALL_ONCE_H | #define CALL_ONCE_H | ||
#include < | #include <QtGlobal> | ||
#include < | #include <QAtomicInt> | ||
#include < | #include <QMutex> | ||
#include < | #include <QWaitCondition> | ||
#include < | #include <QThreadStorage> | ||
#include < | #include <QThread> | ||
namespace CallOnce { | namespace CallOnce { | ||
Line 27: | Line 24: | ||
template <class Function> | template <class Function> | ||
inline static void qCallOnce(Function func, QBasicAtomicInt& | inline static void qCallOnce(Function func, QBasicAtomicInt& flag) | ||
{ | { | ||
using namespace CallOnce; | using namespace CallOnce; | ||
Line 33: | Line 30: | ||
if (protectFlag CO_Finished) | if (protectFlag CO_Finished) | ||
return; | return; | ||
if (protectFlag CO_Request & | if (protectFlag CO_Request && flag.testAndSetRelaxed(protectFlag, | ||
CO_InProgress)) { | CO_InProgress)) { | ||
func(); | func(); | ||
Line 57: | Line 54: | ||
#endif // CALL_ONCE_H | #endif // CALL_ONCE_H | ||
</code> | </code> | ||
This is example how to use this functions for set thread priority once per thread at run: | This is example how to use this functions for set thread priority once per thread at run: | ||
<code> | <code> | ||
#include < | #include <QtGlobal> | ||
#include < | #include <QtDebug> | ||
#include < | #include <QTimer> | ||
#include < | #include <QTime> | ||
#include < | #include <QVector> | ||
#include < | #include <QThread> | ||
#include < | #include <QtConcurrentMap> | ||
#include < | #include <QtConcurrentFilter> | ||
#include < | #include <QCoreApplication> | ||
#include <algorithm> | #include <algorithm> | ||
Line 131: | Line 128: | ||
} | } | ||
int calculate(const int& | int calculate(const int& num) | ||
{ | { | ||
#if 0 // Test once call per thread with function | #if 0 // Test once call per thread with function | ||
Line 152: | Line 149: | ||
static QBasicAtomicInt flag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request); | static QBasicAtomicInt flag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request); | ||
int parityFilter(const int& | int parityFilter(const int& num) | ||
{ | { | ||
qCallOnce(run_once(), flag); | qCallOnce(run_once(), flag); | ||
Line 192: | Line 189: | ||
</code> | </code> | ||
[http://www.forum.crossplatform.ru/index.php?act=attach& | [http://www.forum.crossplatform.ru/index.php?act=attach&type=post&id=1102 Source] | ||
P.S.: | P.S.: This implementation faster than boost::call_once, but slower than std::call_once |
Latest revision as of 02:35, 18 May 2017
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 <QtGlobal>
#include <QAtomicInt>
#include <QMutex>
#include <QWaitCondition>
#include <QThreadStorage>
#include <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& flag)
{
using namespace CallOnce;
int protectFlag = flag.fetchAndStoreAcquire((int)flag);
if (protectFlag CO_Finished)
return;
if (protectFlag CO_Request && 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 <QtGlobal>
#include <QtDebug>
#include <QTimer>
#include <QTime>
#include <QVector>
#include <QThread>
#include <QtConcurrentMap>
#include <QtConcurrentFilter>
#include <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& 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& 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;
}
P.S.: This implementation faster than boost::call_once, but slower than std::call_once