Qt wiki will be updated on October 12th 2023 starting at 11:30 AM (EEST) and the maintenance will last around 2-3 hours. During the maintenance the site will be unavailable.
Set Thread Priority In 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 <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