I have tried three different approaches to this multithreading problem and I am observing the same result no matter which way I go.
The first version is the blocking QtConcurrent::blockingMap() call:
class Experimenter
: public QThread{
QVector<ExperimentConfig> cases;
}
void Experimenter::runExperiments()
{
QtConcurrent::blockingMap(cases, [this] (ExperimentConfig& ex) { processCase(ex); });
}
void Experimenter::processCase(ExperimentConfig& ex)
{
// compute many things
}
class Experimenter : public QThread
{
QVector<ExperimentConfig> cases;
}
void Experimenter::runExperiments()
{
QtConcurrent::blockingMap(cases, [this] (ExperimentConfig& ex) { processCase(ex); });
}
void Experimenter::processCase(ExperimentConfig& ex)
{
// compute many things
}
To copy to clipboard, switch view to plain text mode
In the second version, I use QtConcurrent::run() to launch threads and watch QFuture objects to see when a thread has finished:
void Experimenter::runExperiments()
{
const static uint threads = 5;
Vector<QFuture<void> > results(threads);
bool finished = false;
uint k = 0;
while (!finished)
{
for (uint i = 0; i < threads; i++)
{
if (results[i].isFinished() && k < cases.size())
{
qDebug() << "Thread" << i << "is now working on case" << k;
results[i] = QtConcurrent::run(this, &Experimenter::processCase, cases[k++]);
}
}
if (k >= cases.size())
finished = true;
sleep(10);
}
}
void Experimenter::runExperiments()
{
const static uint threads = 5;
Vector<QFuture<void> > results(threads);
bool finished = false;
uint k = 0;
while (!finished)
{
for (uint i = 0; i < threads; i++)
{
if (results[i].isFinished() && k < cases.size())
{
qDebug() << "Thread" << i << "is now working on case" << k;
results[i] = QtConcurrent::run(this, &Experimenter::processCase, cases[k++]);
}
}
if (k >= cases.size())
finished = true;
sleep(10);
}
}
To copy to clipboard, switch view to plain text mode
In the third version, I start() my own QThread objects and watch their isRunning() status to see when they have finished:
class WorkerThread
: public QThread{
public:
ExperimentConfig ex;
void run()
{
processCase(ex);
}
void processCase(ExperimentConfig& ex);
};
void Experimenter::runExperiments()
{
const static uint threads = 5;
WorkerThread thread[threads];
bool finished = false;
uint k = 0;
while (!finished)
{
for (uint i = 0; i < threads; i++)
{
if (!thread[i].isRunning() && k < cases.size())
{
qDebug() << "Thread" << i << "is now working on case" << k;
cases[thread[i].ex.id] = thread[i].ex;
thread[i].ex = cases[k++];
thread[i].start();
}
}
if (k >= cases.size())
finished = true;
sleep(10);
}
}
class WorkerThread : public QThread
{
public:
ExperimentConfig ex;
void run()
{
processCase(ex);
}
void processCase(ExperimentConfig& ex);
};
void Experimenter::runExperiments()
{
const static uint threads = 5;
WorkerThread thread[threads];
bool finished = false;
uint k = 0;
while (!finished)
{
for (uint i = 0; i < threads; i++)
{
if (!thread[i].isRunning() && k < cases.size())
{
qDebug() << "Thread" << i << "is now working on case" << k;
cases[thread[i].ex.id] = thread[i].ex;
thread[i].ex = cases[k++];
thread[i].start();
}
}
if (k >= cases.size())
finished = true;
sleep(10);
}
}
To copy to clipboard, switch view to plain text mode
The observed behavior in all cases is that the threads are interleaved correctly, they do run at the same time, but apparently they are all run on the same core. In htop, I can see only one core peaking at 100% and the threads I created are fluctuating between 0% an 100%, mostly one at a time, sometimes two threads adding up to 100%. It seems to me that all started threads are processed on the same core and are thus interrupted a lot by round robin. When I start a second process that again launches its own threads, I can see two cores being loaded to 100%. Why aren't the threads running on different cores?
The question whether cases are mutexed is good thinking, but unfortunately no, this is not the case. Or at least not that I am aware of.
cases is a QVector of objects as shown in the first code snippet above. Parallel access through the [] operator should be no problem, right?
Otherwise, the threads give qDebug output and perform unmutexed file write operations which hasn't been an issue so far.
Bookmarks