QEventLoop for synchronous wait for signal - c++

I'm using Qt5, QCoreApplication.
In order to allow for readable and easy to maintain code, I need to write a blocking method in a class/thread A that will emit a signal, connected to a slot in a different thread B, and then wait for an answer or a timeout to occur asynchronously in thread B.
I have first been thinking about what felt like a natural solution: let thread B reply with a signal connected to a slot in thread A, and somehow wait for it. It seems QEventLoop can do that for me. But I keep reading contradictory statements: that's the pattern but avoid it if you can :-).
I'm pretty sure I could achieve my purpose by blocking A on a 0 QSemaphore that B would release when ready. The code would probably not be much more complex that way.
What do you experienced Qt developers think?
Is there a good solution or do you find some symptoms of flawed analysis in my description (i.e. do you think I should never ever need to do something like that? :-))?

The key ingredient you can leverage is the Qt::BlockingQueuedConnection.
This connection type lets you pass return value from a slot. You can use it in a signal-slot connection. You can also directly invoke the slot without using a signal through the QMetaMethod::invoke / QMetaObject::invokeMethod mechanism.
#include <QDebug>
#include <QThread>
#include <QCoreApplication>
class Master : public QObject {
Q_OBJECT
public:
Q_SIGNAL bool mySignal();
Q_SLOT void process() {
if (mySignal()) { // this can be a blocking call
qDebug() << "success!";
}
thread()->quit();
}
};
class Slave : public QObject {
Q_OBJECT
public:
Q_SLOT bool mySlot() {
// do whatever processing is needed here
// It's OK to call QCoreApplication::processEvents here
return true;
}
};
int main(int argc, char** argv) {
QCoreApplication app(argc, argv);
QThread masterThread, slaveThread;
Master master;
Slave slave;
master.moveToThread(&masterThread);
slave.moveToThread(&slaveThread);
slave.connect(&master, SIGNAL(mySignal()), SLOT(mySlot()),
Qt::BlockingQueuedConnection);
masterThread.start();
slaveThread.start();
QMetaObject::invokeMethod(&master, "process");
masterThread.wait();
slaveThread.quit();
slaveThread.wait();
return 0;
}
#include "main.moc"

if you just want to emit a signal in your thread, which means your main thread will have a slot to connect you thread signal, it is simple, just emit it.
but if you want a slot in your thread, and receive signal and so something in your thread, you have to use QEventloop in you run method.
usually, I will just use QThread::wait to wait for other thread end.
be careful here, some Qt objects cannot work across the thread like QSql* and QTcpSocket....

Related

Thread safety of emitting Qt signals

I'm using QtConcurrent::run (I know other APIs of QtConcurrent has built in support for progress reporting but I can't use them for other reasons). to run an operation inside a different than the main GUI thread. I also need this operation to notify the GUI thread of the progress made. So what I did is that created a separate function for the operation I want which accepts a callback that carries the information about the progress of the operation. This callback then calls the signal on a QObject living in the main thread.
Here is a full working example that shows my structure:
#include <QCoreApplication>
#include <QObject>
#include <QThread>
#include <QtConcurrent/QtConcurrent>
namespace Operations {
template<typename Callback>
void longOperation(Callback progressCallback)
{
qint64 sum = 0;
for(int i = 0; i < 100; ++i){
QThread::msleep(400);
sum += i;
progressCallback(i/100.0);
}
}
}
class Emitter : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE void doSomething()
{
auto progressCallback = [&](qreal p){
emit progress(p);
};
auto lambda = [progressCallback](){
Operations::longOperation(progressCallback);
};
QtConcurrent::run(lambda);
}
signals:
void progress(qreal);
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Emitter emitter;
QObject::connect(&emitter, &Emitter::progress, [](qreal progress){
qDebug() << "Progress" << progress;
});
emitter.doSomething();
return a.exec();
}
#include "main.moc"
Now my question is using the progressCallback as defined above thread safe? The callback will clearly be triggered from a thread different than the GUI thread, so effectively it's calling emitter.progress() directly on the QObject.
Ok, so I now realised that the code above may not be thread safe. Part of my confusion was what does the emit keyword actually does. It turns out it's actually not much at all. So calling the signal from another thread is not really the best idea.
Instead, one of way of improve the situation is replace the progressCallback with:
auto progressCallback = [&](qreal p){
QMetaObject::invokeMethod(this, [this, p](){ emit progress(p);}, Qt::QueuedConnection);
};
This way the signal is emitted on the thread where the Emitter lives as the lambda slot will be executed "when control returns to the event loop of the receiver's thread" as per the Qt documentation.

Creating QNetworkAccessManager in another thread

I have a QNetworkAccessManager created in another thread.
The network is meant to be used only in MyMegaThread.
QNetworkAccessManager is created from the thread's run method:
mp_manager.reset(new QNetworkAccessManager{this});
On creation I get such a message in console:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is MyMegaThread(0x237eabd0ee0), parent's thread is QThread(0x237e70742a0), current thread is MyMegaThread(0x237eabd0ee0)
This message is totally harmless, but I wonder which parent the manager is supposed to have.
I suspect it happens because the MyMegaThread instance is created in the main thread, but I need a parent created in MyMegaThread instead.
What is an idiomatic way of doing this?
Parent is MyMegaThread(0x237eabd0ee0), parent's thread is
QThread(0x237e70742a0), current thread is MyMegaThread(0x237eabd0ee0)
The issue does not relate to QNetworkAccessManager.
Here is the demo to reproduce the warning.
#include <QDebug>
#include <QThread>
class MyMegaThread : public QThread
{
Q_OBJECT
public:
using QThread::QThread;
protected:
void run() override {
qDebug()<<QThread::currentThread()<<this->thread();
new QObject(this);
}
};
// main
MyMegaThread m;
m.start();
Output:
MyMegaThread(0x60fe18) QThread(0x16a7c48)
It's rule of QObject:
All QObjects must live in the same thread as their parent.
Consequently:
setParent() will fail if the two QObjects involved live in different
threads. When a QObject is moved to another thread, all its children
will be automatically moved too. moveToThread() will fail if the
QObject has a parent. If QObjects are created within QThread::run(),
they cannot become children of the QThread object because the QThread
does not live in the thread that calls QThread::run().
http://doc.qt.io/qt-5/qobject.html#thread-affinity
Have to make sure this code new QObject running QThread be same as given parent QObject thread.
mp_manager.reset(new QNetworkAccessManager{this});
No, the message is not harmless at all. The object you have created has a null parent and no reference on the thread association and thus its thread() method may return a dangling pointer at any time. It cannot safely use timers nor receive cross-thread calls. It is basically as useless object, and you're asking for undefined behavior to strike. This shouldn't be a warning, but a failure. Qt did you a disservice here by allowing you to continue.
The idiomatic way of doing it is first of all not to derive from QThread. QThread is a thread handle. It wraps a system resource. Put all of your functionality into a regular QObject moved into a QThread. The idiomatic way to endlessly "do stuff" on any thread, including the main thread, is to use a zero-duration timer. Note that zero-duration timers have nothing to do with timing at all. They are essentially event loop handles, calling them a timer is a misnomer.
To wit:
// https://github.com/KubaO/stackoverflown/tree/master/questions/thread-simple-50632807
#include <QtNetwork>
class Thread final : public QThread {
Q_OBJECT
public:
void takeObject(QObject *obj) {
obj->moveToThread(this);
}
~Thread() override {
requestInterruption();
quit();
wait();
}
};
class Class : public QObject {
Q_OBJECT
QBasicTimer m_workTimer;
QNetworkAccessManager m_manager{this};
void doWorkChunk() {
qDebug() << "tick...";
QThread::sleep(1); // emulate a blocking operation
}
protected:
void timerEvent(QTimerEvent *ev) override {
if (ev->timerId() != m_workTimer.timerId())
return;
doWorkChunk();
}
public:
explicit Class(QObject *parent = {}) : QObject(parent) {
m_workTimer.start(0, this);
}
};
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
Class object;
Thread workThread;
workThread.start();
workThread.takeObject(&object);
QTimer::singleShot(3000, &QCoreApplication::quit);
return app.exec();
}
#include "main.moc"
The QBasicTimer::stop: Failed. Possibly trying to stop from a different thread warning is relatively benign and indicates an internal timer handle leak. For a workaround, see this answer.

Correct way to signal QObject on another thread?

Let's say I have a slave object that lives in another thread. I want to tell it to do A, B, C on that thread. I can think of 3 ways of doing it:
(1) Using QTimer::singleShot
(2) Using QMetaObject::invokeMethod
(3) Creating another master object and connecting its signal to the slave
Following is an example:
class slave : public QObject
{
QThread thread_;
friend class master;
void do_A(params);
void do_B(params);
void do_C(params);
public:
slave() { thread_.start(); moveToThread(&thread_); }
~slave() { thread_.quit(); thread_.wait(); }
void que_A(params) { QTimer::singleShot(0, [&](){ do_A(params); }); } // (1)
void que_B(params) { QMetaObject::invokeMethod(this, "do_B", params); } // (2)
}
class master : public QObject // (3)
{
Q_OBJECT
public:
master(slave* s) { connect(this, &master::que_C, s, &slave::do_C); }
void do_C(params) { emit que_C(params); }
signals:
void que_C(params);
}
My concerns are:
(1) I am abusing QTimer.
(2) Using strings for signals/slot is so qt4. Qt5 uses new syntax.
(3) Too much boilerplate.
Is any of the methods considered more correct compared to the others? Or can anybody think of a better way?
Please include your reasoning (not just opinion) why one method should be chosen over others.
UPDATE:
In my real-world application I have another class -- let's call it owner -- that owns several slaves. The owner needs to tell different slaves to do different things (A, B or C) depending on user input. The slaves are stateful objects, so I cannot see an easy way of using concurrency functions (eg, std::async or QtConcurrency).
Well, I will not comment (1) and (2) but I must say that (3) is the one usually used. However, I understand your concern about too much boilerplate. After all, creating a separate signal, say doActionA(), connecting it via QueuedConnection to some real actionA() and at last emitting it... too much noise and useless moves.
Indeed, the only benefit it gives you is a loose coupling (you can send a signal being not aware of existence of slots connected to it). But if I create a signal with a name doActionA() of course I am aware of actionA() existence. So then the question is starting to raise "Why do I have to write all this stuff?"
Meanwhile, Qt kind of provides the solution to this problem giving you the ability to post your own events to any event loop (and as you know QThread has one). So, implement it once and you do not need to write a lot of connect emit stuff any more. Also, I suppose I is more efficient because all in all, every slot invokation via QueuedConnection just posts an event in an event loop.
Here InvokeAsync posts the event for member function execution into the event loop of the thread where QObject lives:
#include <QCoreApplication>
#include <QEvent>
#include <QThread>
#include <string>
#include <iostream>
#include <type_traits>
#include <functional>
template<typename T, typename R, typename ... Params, typename... Args>
void InvokeAsync(T* object, R (T::*function)(Params...), Args&&... args)
{
struct Event : public QEvent
{
std::function<R ()> function;
Event(T* object, R (T::*function)(Params...), Args&& ... args)
: QEvent{ QEvent::None },
function{ std::bind(function, object, std::forward<Args>(args)...) }
{
}
~Event() { function(); }
};
QCoreApplication::postEvent(object, new Event{ object, function, std::forward<Args>(args)... });
}
struct Worker : QObject
{
void print(const std::string& message, int milliseconds)
{
QThread::currentThread()->msleep(milliseconds);
std::cout << message
<< " from thread "
<< QThread::currentThreadId() << std::endl;
}
};
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
std::cout << "GUI thread " << QThread::currentThreadId() << std::endl;
QThread thread;
thread.start();
Worker worker;
worker.moveToThread(&thread);
InvokeAsync(&worker, &Worker::print, "Job 1", 800);
InvokeAsync(&worker, &Worker::print, "Job 2", 400);
InvokeAsync(&worker, &Worker::print, "Job 3", 200);
a.exec();
return 0;
}
Output:
GUI thread 00000000000019C8
Job 1 from thread 00000000000032B8
Job 2 from thread 00000000000032B8
Job 3 from thread 00000000000032B8
As you see all jobs where done in a different thread in order of their invocation. Qt guarantees that events with the same priority are processed in order as they were posted.
Also it is OK, if worker lives in GUI thread. Events will be just posted in GUI event loop and processed later (that is why I called those Async).
If you see any mistakes or have some remarks, please, write in comments and we will figure it out.
I am not pretty sure I understood well the question.
So I will explain here how to manage thread in Qt (in summarized way).
First, QThreadclass is not really meant to be inherited from.
Instead, make something like this :
class Slave : public QObject {
Slave(QThread *thread) {moveToThread(thread);)
};
QThread thread;
Slave slave(&thread);
After, you normally can use signal and slots in the normal way.
However, if your objective is only to "run a function inside another thread", maybe QConcurrent could be a better way?
In fact, the Qt documentation provides a very nice example that probably answers your question on how to use QThread. It's the following:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString &parameter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
The idea here is simple. You have a worker, which is running in the thread. You also have the controller, which is basically your main thread that submits work to the other thread. The thread will (thread-safely) emit the resultReady() signal when it's finished. Signals and slots are thread-safe here, as long as they use Qt::QueuedConnection to communicate.

QThread::wait() does not return without using direct connection

I got some trouble with Qt Threads and Connections. I found several tutorials and discussions on this topic, I followed this tutorial to create the thread. But I still got the problem, that calling wait() on the thread never returns and the UI freezes.
A similar question was asked here before (the second example):
Qt connection type between threads: why does this work?
In the last edit of the question, the author mentions that he had created a deadlock. I assume, I do the same in my application. But I still do not understand, why this happens. Reading the suggested article did not help me understanding. I just got the point, that deadlocks can happen, but I don't know, what's causing it there or in my case.
I have also created an example that's reduced to the core problem. Find the code at the bottom of this question.
So my questions are:
What exactly is the cause for the deadlock in my example?
Is there a solution without making the connection a direct connection?
I'd really appreciate any hints.
Thanks!
EDIT:
Because of the comments I tried it to send the stop request via a signal and I added a QCoreApplication::processEvents() call in the thread loop. But the main problem is still the same.
EDIT2:
I found an acceptable solution, after thinking a bit more about event loops:
thread.requestStop();
// now instead of using wait(), we poll and keep the event loop alive
// polling is not nice, but if it does not take a very long time
// for the thread to finish, it is acceptable for me.
while (thread.isRunning())
{
// This ensures that the finished() signal
// will be processed by the thread object
QCoreApplication::processEvents();
}
This actually works and the worker itself controls how to stop working.
After coming up with this, I also have an explanation for the freezing issue: Calling wait seems to keep the main thread either busy or suspended so it does not process any events. Since the thread object lives in the main thread, the thread's finished() signal is enqued but never processed.
My implicit assumption, that thread.wait() would still keep the event loop working, was obviously wrong. But then, what's the QThread::wait() function good for?!?
This is just a theory, but maybe someone here can verify or falsify it...
EDIT 3 (final solution):
After reading this small article and implmenting a subclassing solution, I think that this is preferable for this particular proble. There is no need for an event loop and I'm fine with direct calls on a different thread and using mutex protection. It's less code, easier to understand and easier to debug.
I think I would use the non-subclassing strategy only, if there were more interaction with the thread than just start and pause.
My reduced Example
Maybe I should point out, that I do not delete the thread, because in my original application, I want to resume later, so stopping it actually means pausing it.
worker.h:
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QMutex>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject* parent = NULL);
public slots:
void doWork();
void requestStop();
signals:
void finished();
private:
bool stopRequested;
QMutex mutex;
};
#endif // WORKER_H
worker.cpp:
#include "worker.h"
#include <QThread>
#include <iostream>
using namespace std;
Worker::Worker(QObject *parent)
: stopRequested(false)
{
}
void Worker::doWork()
{
static int cnt = 0;
// local loop control variable
// to make the usage of the mutex easier.
bool stopRequesteLocal = false;
while (!stopRequesteLocal)
{
cout << ++cnt << endl;
QThread::msleep(100);
mutex.lock();
stopRequesteLocal = stopRequested;
mutex.unlock();
}
cout << "Finishing soon..." << endl;
QThread::sleep(2);
emit finished();
}
void Worker::requestStop()
{
mutex.lock();
stopRequested = true;
mutex.unlock();
}
main program:
#include <QCoreApplication>
#include <QThread>
#include <QtCore>
#include <iostream>
#include "worker.h"
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThread thread;
Worker worker;
QObject::connect(&thread, SIGNAL(started()), &worker, SLOT(doWork()));
// this does not work:
QObject::connect(&worker, SIGNAL(finished()), &thread, SLOT(quit()));
// this would work:
//QObject::connect(&worker, SIGNAL(finished()), &thread, SLOT(quit()), Qt::DirectConnection);
// relocating the moveToThread call does not change anything.
worker.moveToThread(&thread);
thread.start();
QThread::sleep(2);
worker.requestStop();
cout << "Stop requested, wait for thread." << endl;
thread.wait();
cout << "Thread finished" << endl;
// I do not know if this is correct, but it does not really matter, because
// the program never gets here.
QCoreApplication::exit(0);
}
I added my own answere to the question text as EDIT 3.
The first issue I see is that you're not using signals and slots to communicate between the objects running on different threads; main and the new thread that hosts the worker object.
You move the worker object to the second thread, but call a function on the worker object from the main thread: -
thread.start();
QThread::sleep(2);
worker.requestStop(); // Aaahh, this is running on the new thread!!!
Considering that a thread has its own stack and registers I really don't see how this is safe.
If you use signals and slots, Qt handles a lot of threading issues. While you should be able to use a variable to control the 2nd thread, it would also be cleaner to use signals and slots.
Note that when a signal is emitted from one thread, a message is posted to the thread of the receiving object, if the sender and receiver are on separate threads.
Convert your code to use signals and slots for communicating between objects on different threads and your deadlock should disappear.
It doesn't look like you have read that article completely.
QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
You have only implemented partially of what is suggested on the article.
QThread::wait() will wait until QThread::finished() is emitted from doWork(). Please emit this SIGNAL if you need to quit from this thread and return to the main thread. For this you need to keep a reference of the thread on which this object is moved to.

Howto make a simple Qt console application with multithreading?

I have a very difficult time of understanding how to make a simplest possible working
multithreaded Qt console application.
I have read tons of stuff on how to use QThread class.
Some of them say subclass QThread, others say use worker class wrapper for QThread.
After several tries and retries I could still not make a working multithreaded
Qt console application.
Right now I don't need any fancy Qt Gui.
Can someone please help me to fill the threading parts of the example code ?
It just reads one line at the time from text file and the idea is that each thread (I want to use 4 threads) that is not busy at the moment will print that line to stdout with std::cout as soon as possible. Just print it, no other fancy processing stuff for now to keep this simple for me.
#include <QCoreApplication>
#include <QFile>
#include <iostream>
/* QThread stuff here */
/* Don't know how to make it */
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
/* Create four instances of threads here and
put them to wait readed lines */
QFile file("file.txt");
file.open(QIODevice::ReadOnly | QIODevice::Text);
while(!file.atEnd()) {
/* Read lines here but where should they be saved?
Into a global variable like QList<QByteArray> list ?
So that each thread can read them from there or where ???? */
??? = file.readLine();
}
file.close();
a.exit();
}
Putting the Functionality in a Slot in a QObject
The key points are:
Remember that each QObject has a certain thread() that it "lives" in. Each thread can have an event loop running there. This event loop will deliver the events sent to the objects that "live" in this thread.
Do not derive from QThread. Start stock QThreads. They'll start an even event loop in the default implementation of QThread::run().
Implement your functionality in a slot (or a Q_INVOKABLE) method. The class obviously has to derive from QObject.
The magic happens when you send signals (using signal-slot connection, not directly) to the slot in #3. The connection from the notifier, running in the GUI thread, to the notified objects is done automatically using the Qt::QueuedConnection since the sender and the receiver objects live in different threads.
Sending a signal to such an object results in posting an event to the event queue of the thread the object is in. The event loop's event dispatcher will pick those events and call the appropriate slots. This is the power of Qt - a lot of useful stuff can be done for you.
Note that there is no notion of a "currently busy" thread. The threads execute short slots of the objects that live there. If you want to move threads between a "busy" and "not busy" states, then you'd need extra code for that.
Another way of implementing it would be to derive from QRunnable and use QThreadPool. That's in another answer.
main.cpp
#include <QCoreApplication>
#include <QTextStream>
#include <QThread>
#include <QFile>
#include <cstdio>
class Notified : public QObject {
Q_OBJECT
QTextStream m_out;
public:
Q_SLOT void notify(const QString & text) {
m_out << "(" << this << ") " << text << endl;
}
Notified(QObject *parent = 0) : QObject(parent), m_out(stdout) {}
};
class Notifier : public QObject {
Q_OBJECT
Q_SIGNAL void notification(const QString &);
public:
Notifier(QObject *parent = 0) : QObject(parent) {}
void notifyLines(const QString & filePath) {
QFile file(filePath);
file.open(QIODevice::ReadOnly | QIODevice::Text);
while (! file.atEnd()) {
emit notification(file.readLine());
}
file.close();
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QObjectList notifieds;
QList<QThread*> threads;
Notifier notifier;
for (int i = 0; i < 4; ++i) {
QThread * thread = new QThread(&a); // thread owned by the application object
Notified * notified = new Notified; // can't have an owner before it's moved to another thread
notified->moveToThread(thread);
thread->start();
notifieds << notified;
threads << thread;
notified->connect(&notifier, SIGNAL(notification(QString)), SLOT(notify(QString)));
}
notifier.notifyLines("file.txt");
foreach (QThread *thread, threads) {
thread->quit();
thread->wait();
}
foreach (QObject *notified, notifieds) delete notified;
a.exit();
}
#include "main.moc"
For your purposes I would not use QThread at all but the classes from QtConcurrent.
Something simple like (assuming you have C++11):
while(!file.atEnd()) {
QString line = file.readLine();
QtConcurrent::run([line]
{
qDebug() << line;
});
}
Though I'm still not sure what this should give you on a high level.
Below link can be useful for you for the information related to using threads in Qt
http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
If you only want file reading to be done in Asynchronous ways Qt is having several alternate techniques like QtConcurrent.
http://qt-project.org/doc/qt-4.8/threads-qtconcurrent.html
Here is some example code to help you for using QtConcurrent
Running a Function in a Separate Thread
extern QString aFunction();
QFuture<void> future = QtConcurrent::run(aFunction);
aFunction should contain the code for reading the file .
You can return the read data in the following way
QFuture<QString> future = QtConcurrent::run(aFunction);
...
QString result = future.result();
Note that the QFuture::result() function blocks and waits for the result to become available. Use QFutureWatcher to get notification when the function has finished execution and the result is available.
Hope this helps. All the above code is taken from Qt documentation.
Putting the functionality in a QRunnable
Perhaps the solution that's closest to your explicit needs would use a QThreadPool. It does what you want: it picks a non-busy thread from its pool, and runs the worker there. If there are no free threads, it'll add the runnable to a run queue that gets drained each time a free thread becomes available.
Note, though, that your explicit wish of having a thread state, namely busy/non-busy, does not really mesh at all with a network penetration system that needs to wait for a reply before trying each new password. You'll want it based on QObjects. I'll modify my other answer to show how you might do it while managing network connections. It's very, very wasteful to waste threads on busy waiting for network answers. You do not want to do that. It will perform poorly.
Your application is I/O bound and could, pretty much, run on one thread without much in the way of undue performance loss. Only if you have a huge network pipe and are testing tens of thousands of accounts at the same time would you need more than one thread. I'm serious.
#include <QCoreApplication>
#include <QTextStream>
#include <QRunnable>
#include <QThreadPool>
#include <QFile>
#include <cstdio>
class Data : public QString {
public:
Data(const QString & str) : QString(str) {}
};
class Worker : public QRunnable {
QTextStream m_out;
Data m_data;
public:
void run() {
// Let's pretend we do something serious with our data here
m_out << "(" << this << ") " << m_data << endl;
}
Worker(const Data & data) : m_out(stdout), m_data(data) {}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThreadPool * pool = QThreadPool::globalInstance();
QFile file("file.txt");
file.open(QIODevice::ReadOnly | QIODevice::Text);
while (! file.atEnd()) {
const Data data(file.readLine());
Worker * worker = new Worker(data);
pool->start(worker);
}
file.close();
pool->waitForDone();
}