Set Thread Priority In QtConcurrent: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
(hmm ? Had a closing code tag but only format properly with extra newline before closing code tag) |
||
(9 intermediate revisions by 4 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. | |||
<code> | |||
#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 | |||
</code> | |||
This is example how to use this functions for set thread priority once per thread at run: | |||
<code> | |||
#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; | |||
} | |||
</code> | |||
[http://www.forum.crossplatform.ru/index.php?act=attach&type=post&id=1102 Source] | |||
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