Cannot use QtNetwork because application uses different Threads - c++

A strange behavior occured in my application when I'm using QtNetwork. I can easily create the QTcpSever and QTcpSocket instance and everything runs fine, but when it comes to QTcpSocket::write() the following error occurs:
The error
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x7f66980022e0), parent's thread is QThread(0x7f66a0020be0), current thread is QThread(0x7f66a0020e20)
QSocketNotifier: Can only be used with threads started with QThread
What is strange to me: I have no idea what/where this QThread(0x7f66a0020e20) is and how to get influence on it (have a look at the debugging below)
The program
I'm extending my main application (which is a library) with a network support. I put the network services into an extra class.
here the excerpt of the main application/library, where my network support is created:
QThread *thread = new QThread;
wifi = new WirelessNet(0, thread);
wifi->moveToThread(thread);
connect(thread,SIGNAL(started()), wifi,SLOT(initWifi()));
thread->start();
the network class extension:
WirelessNet::WirelessNet(QObject *parent, QThread *comThread): QTcpServer(parent)
{
clientThread = comThread;
}
void WirelessNet::initWifi()
{
listen(QHostAddress::Any, 5220);
connect(this,SIGNAL(newConnection()),this,SLOT(connectionRequest()));
}
void WirelessNet::connectionRequest()
{
client = this->nextPendingConnection();
if(client)
connect(client, SIGNAL(readyRead()), this, SLOT(receiveMessage()));
}
void WirelessNet:sendData(QByteArray msg)
{
if (client)
{
qDebug()<<"FIRST "<< client->thread() << " - " << this->thread() << "\n";
client->write(msg);
client->waitForBytesWritten();
qDebug()<<"LAST " << client->thread() << " - " << this->thread() << "\n";
}
}
(client and clientThread are class members: QTcpSocket*, QThread* respectively)
The debugging
Here is what the console prints out when it comes to the sendData() part:
FIRST QThread(0x7f66a0020be0) - QThread(0x7f66a0020be0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x7f66980022e0), parent's thread is QThread(0x7f66a0020be0), current thread is QThread(0x7f66a0020e20)
QSocketNotifier: Can only be used with threads started with QThread
LAST QThread(0x7f66a0020be0) - QThread(0x7f66a0020be0)
Concluding
In other words I have no idea on which object I should apply the moveToThread(). I already tried client->moveToThread(clientThread) aswell as this->moveToThread(clientThread). Unfortunately I don't see any additional objects to check on.
Has anyone an idea ?

You seem to be calling WirelessNet:sendData directly from the main thread. This causes everything inside that function to be run in the main thread as well. Your client lives in the new thread, and it is not thread-safe. It tries to create children, but current thread is different from the thread where client lives in. That is why you get that error message.
You can fix it simply by making WirelessNet:sendData a slot and call it via a signal from the main thread.

My guess is that the constructor of your class is called in the calling thread, while the thread itself runs in the run() method of your class. The solution would be to initialize QTcpServer at the beginning of your run() method, so that initialization and communication through that class is done in the very same thread.

Related

Programming with QThread multithreading in C++

I am trying to learn little bit about Multi-Threading because I need it in my bachelor thesis. I think I understand it on low teoretical level but not on practical.
For the beginning I am trying to create very easy program, where I would like to learn how to work with QThread. My small program test all files in directory if they are .txt files.
There is function which just test if one file contains .txt and its used in next functions.
I know I know this is not perfect test for testing if file is .txt but it really doesnt matter. This is about something else.
void FileTester::testIfTxt(QString &file){
if( file.contains(".txt"))
std::cout << file.toStdString() << " is .txt file" << std::endl;
else
std::cout << file.toStdString() << " is NOT .txt file" << std::endl;
}
Here is function for testing without using multi-threading.
void FileTester::normalTest(){
QDir folderPath("D:\\programming\\C++\\multithreading-qt\\files");
QStringList filesList = folderPath.entryList(QDir::NoDotAndDotDot | QDir::Files);
auto t_start = std::chrono::high_resolution_clock::now();
for(QString& file : filesList){
testIfTxt(file);
}
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms = std::chrono::duration<double, std::milli>(t_end-t_start).count();
std::cout << elapsed_time_ms << " ms" << std::endl;
}
Now I would like to do the same but with multithreading. For the beginning we can use 3 threads. First thread would take first file and test, while second thread would take second file and test and third thread would take third file and test. When first thread will end work, than take nex untested file and test etc. .......
I started with function there but I really dont understand, how to use something like this. I started with something like this.
void FileTester::multiThreadTest(){
auto t_start = std::chrono::high_resolution_clock::now();
allMultiThreadTest();
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms = std::chrono::duration<double, std::milli>(t_end-t_start).count();
std::cout << elapsed_time_ms << " ms" << std::endl;
}
void FileTester::allMultiThreadTest(){
QThread* thread1 = new QThread();
QThread* thread2 = new QThread();
QThread* thread3 = new QThread();
thread1->start();
thread2->start();
thread3->start();
for(QString& file : filesList){
testIfTxt(file);
}
}
Again this is not code from my bachelor thesis. I just want to learn how to use multithreading on this easy program. Thank you for any help.
The QThread documentation, like most Qt documentation, is very good, but the code examples might be a bit overwhelming.
There are basically two ways to use QThread:
Subclassing QThread
Useful when you want to run some code on a thread, and exit the thread when the code finishes.
Create a subclass of QThread and override its run() function. The code you put in that function will run in the thread, and when the function returns, the thread exits.
To start the thread, simply create an instance of your subclass and call start() on it.
Handling signals on a thread
Useful when you want to keep a thread in the background, and occasionally send it some work to do. This approach needs some boilerplate code because you need an object to emit a signal and another object to receive it with a slot.
Create a subclass of QObject and give it a public slot of your choice.
Create an instance of QThread (no subclass needed here). The default implementation of run() contains an event loop, which simply waits for signals and runs the corresponding slots, just like QApplication::exec() does for your main thread.
Create an instance of your QObject subclass. Move the latter to your new thread using QObject::moveToThread(). The effect of this is, that any slots being called by signals will be run on that thread, rather than the main thread. See thread affinity and queued connections.
Connect the slot to a signal that is emitted by any QObject subclass on your main thread.
To send work to the thread, simply emit that signal.
Note: any arguments that you pass to the signal must be known to Qt's meta-type system. Most built-in Qt types are okay. If you run afoul of this rule, you will get a warning at runtime.

Confusion about boost::asio::io_context::run

I am currently working on a project where I use the MQTT protocol for communication.
There is a Session class in a dedicated file which basically just sets up the publish handler, i.e. the callback that is invoked, when this client receives a message (the handler checks if the topic matches "ZEUXX/var", then deserialized the binary content of the frame and subsequently unsubscribes the topic):
session.hpp:
class Session
{
public:
Session()
{
comobj = MQTT_NS::make_sync_client(ioc, "localhost", "1883", MQTT_NS::protocol_version::v5);
using packet_id_t = typename std::remove_reference_t<decltype(*comobj)>::packet_id_t;
// Setup client
comobj->set_client_id(clientId);
comobj->set_clean_session(true);
/* If someone sends commands to this client */
comobj->set_v5_publish_handler( // use v5 handler
[&](MQTT_NS::optional<packet_id_t> /*packet_id*/,
MQTT_NS::publish_options pubopts,
MQTT_NS::buffer topic_name,
MQTT_NS::buffer contents,
MQTT_NS::v5::properties /*props*/) {
std::cout << "[client] publish received. "
<< " dup: " << pubopts.get_dup()
<< " qos: " << pubopts.get_qos()
<< " retain: " << pubopts.get_retain() << std::endl;
std::string_view topic = std::string_view(topic_name.data(), topic_name.size());
std::cout << " -> topic: " << topic << std::endl;
else if (topic.substr(0, 9) == "ZEUXX/var")
{
std::cout << "[client] reading variable name: " << topic.substr(10, topic.size() - 9) << std::endl;
auto result = 99; // dummy variable, normally an std::variant of float, int32_t uint8_t
// obtained by deserialzing the binary content of the frame
std::cout << comobj->unsubscribe(std::string{topic});
}
return true;
});
}
void readvar(const std::string &varname)
{
comobj->publish(serialnumber + "/read", varname, MQTT_NS::qos::at_most_once);
comobj->subscribe(serialnumber + "/var/" + varname, MQTT_NS::qos::at_most_once);
}
void couple()
{
comobj->connect();
ioc.run();
}
void decouple()
{
comobj->disconnect();
std::cout << "[client] disconnected..." << std::endl;
}
private:
std::shared_ptr<
MQTT_NS::callable_overlay<
MQTT_NS::sync_client<MQTT_NS::tcp_endpoint<as::ip::tcp::socket, as::io_context::strand>>>>
comobj;
boost::asio::io_context ioc;
};
The client is based on a boost::asio::io_context object which happens to be the origin of my confusion. In my main file I have the following code.
main.cpp:
#include "session.hpp"
int main()
{
Session session;
session.couple();
session.readvar("speedcpu");
}
Essentially, this creates an instance of the class Session and the couple member invokes the boost::asio::io_context::run member. This runs the io_context object's event processing loop and blocks the main thread, i.e. the third line in the main function will never be reached.
I would like to initiate a connection (session.couple) and subsequently do my publish and subscribe commands (session.readvar). My question is: How do I do that correctly?
Conceptionally what I aim for is best expressed by the following python-code:
client.connect("localhost", 1883)
# client.loop_forever() that's what happens at the moment, the program
# doesn't continue from here
# The process loop get's started, however it does not block the program and
# one can send publish command subsequently.
client.loop_start()
while True:
client.publish("ZEUXX/read", "testread")
time.sleep(20)
Running the io_context object in a separate thread seems not to be working the way I tried it, any suggestions on how to tackle this problem? What I tried is the following:
Adaption in session.hpp
// Adapt the couple function to run io_context in a separate thread
void couple()
{
comobj->connect();
std::thread t(boost::bind(&boost::asio::io_context::run, &ioc));
t.detach();
}
Adpations in main.cpp
int main(int argc, char** argv)
{
Session session;
session.couple();
std::cout << "successfully started io context in separate thread" << std::endl;
session.readvar("speedcpu");
}
The std::cout line is now reached, i.e. the program does not get stuck in the couple member of the class by io_context.run(). However directly after this line I get an error: "The network connection was aborted by the local system".
The interesting thing about this is that when I use t.join() instead of t.detach() then there is no error, however I have the same behavior with t.join() as when I call io_context.run() directly, namely blocking the program.
Given your comment to the existing answer:
io_context.run() never return because it never runs out of work (it is being kept alive from the MQTT server). As a result, the thread gets blocked as soon as I enter the run() method and I cannot send any publish and subscribe frames anymore. That was when I thought it would be clever to run the io_context in a separate thread to not block the main thread. However, when I detach this separate thread, the connection runs into an error, if I use join however, it works fine but the main thread gets blocked again.
I'll assume you know how to get this running successfully in a separate thread. The "problem" you're facing is that since io_context doesn't run out of work, calling thread::join will block as well, since it will wait for the thread to stop executing. The simplest solution is to call io_context::stop before the thread::join. From the official docs:
This function does not block, but instead simply signals the io_context to stop. All invocations of its run() or run_one() member functions should return as soon as possible. Subsequent calls to run(), run_one(), poll() or poll_one() will return immediately until restart() is called.
That is, calling io_context::stop will cause the io_context::run call to return ("as soon as possible") and thus make the related thread joinable.
You will also want to save the reference to the thread somewhere (possibly as an attribute of the Session class) and only call thread::join after you've done the rest of the work (e.g. called the Session::readvar) and not from within the Session::couple.
When io_context runs out of work, it returns from run().
If you don't post any work, run() will always immediately return. Any subsequent run() also immediately returns, even if new work was posted.
To re-use io_context after it completed, use io_context.reset(). In your case, better to
use a work guard (https://www.boost.org/doc/libs/1_73_0/doc/html/boost_asio/reference/executor_work_guard.html), see many of the library examples
don't even "run" the ioc in couple() if you already run it on a background thread
If you need synchronous behaviour, don't run it on a background thread.
Also keep in mind that you need to afford graceful shutdown which is strictly harder with a detached thread - after all, now you can't join() it to know when it exited.

What happens with Qt::BlockingQueuedConnection emission if target object dies?

When I send a method call using invokeMethod, what happens when the sending code waits on the call, but the target object dies subsequently? Will this end in an infinite wait? Or will Qt wake up the caller and return false (which would be an undocumented behavior, and a best guess by myself)?
The following example deletes the worker object while invokeMethod is waiting for a BlockingQueuedConnection:
#include <QtCore>
//a thread that can be destroyed at any time
//see http://stackoverflow.com/a/25230470
class SafeThread : public QThread{
using QThread::run;
public:
explicit SafeThread(QObject* parent= nullptr):QThread(parent){}
~SafeThread(){ quit(); wait(); }
};
//The function queues a functor to get executed in a specified worker's thread
template <typename Func>
void PostToThread(QThread* thread, Func&& f) {
//see http://stackoverflow.com/a/21653558
QObject temporaryObject;
QObject::connect(&temporaryObject, &QObject::destroyed,
thread->eventDispatcher(), std::forward<Func>(f),
Qt::QueuedConnection);
}
//a typical QObject worker that can "printName"
class Worker : public QObject {
Q_OBJECT
public:
using QObject::QObject;
~Worker() {
qInfo() << "destroying " << objectName()
<< " in " << QThread::currentThread()->objectName();
}
Q_SLOT void printName() {
qInfo() << "my name is " << objectName()
<< " in " << QThread::currentThread()->objectName();
}
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
//create worker
Worker *worker = new Worker;
worker->setObjectName("worker");
//start worker thread and move worker to it
SafeThread t;
worker->moveToThread(&t);
t.start();
//set thread names (for better output)
QThread::currentThread()->setObjectName("main_thread");
t.setObjectName("worker_thread");
//normal QMetaObject::invokeMethod usage
if(QMetaObject::invokeMethod(worker, "printName",
Qt::BlockingQueuedConnection)) {
qInfo() << "printName called successfully before deletion";
}
//the lambda function will be executed in the worker thread
PostToThread(&t, [worker]{
qInfo() << "blocking " << QThread::currentThread()->objectName();
QThread::sleep(2); //block worker thread for 2 seconds
delete worker; //delete worker
});
//at this point the worker thread is about to destroy the worker object (but
//hasn't done so yet)
if(QMetaObject::invokeMethod(worker, "printName",
Qt::BlockingQueuedConnection)) {
qInfo() << "printName called successfully after deletion!";
}
QTimer::singleShot(100, &a, &QCoreApplication::quit);
return a.exec();
}
#include "main.moc"
Output (tested on Qt 5.9.1, Qt 5.7 - windows, debian):
my name is "worker" in "worker_thread"
printName called successfully before deletion
blocking "worker_thread"
destroying "worker" in "worker_thread"
printName called successfully after deletion!
So a short answer is: invokeMethod returns true but nothing gets called. However, please note that you have to guarantee that the worker object is still valid at the beginning of (see last point for more details) the invokeMethod call the main thread (otherwise, it is UB).
Here is a list of conclusions that I got into by digging through Qt's code:
ivokeMethod returns false only when there is a problem in the parameters passed to it (e.g. slot signature does not match parameters count/type, return type mismatch, unknown connection type, ...). See here.
When using Qt::BlockingQueuedConnection, invokeMethod blocks the calling thread by acquiring a QSemaphore. The QSemaphore is stored into the QMetaCallEvent that is posted to the receiver object.
This QSemaphore is released when the QMetaCallEvent is destroyed.
QObject's destructor is responsible for calling QCoreApplication::removePostedEvents() for the object being destructed. This means that all the events in the event queue that are targeted to an object are destroyed upon this object's destruction. See here.
You need to make sure that the worker object stays alive while the calling thread executes invokeMethod until the mentioned semaphore is acquired, because invokeMethod might try to access the worker object at any point. I think that this requirement can make things complicated in practice, as one might end up having to guarantee the lifetime of the object throughout the whole invokeMethod call (and hence avoiding this whole question).

Why is a slot being called in receiver's thread even after using Qt::DirectConnection? How do I ensure that it is called in the other thread?

According to the documentation for Qt::ConnectionType in Qt5, using Qt::DirectConnection means that the slot for a given signal is called in the same thread as the signal itself, even if the object the slot belongs to lies in a different thread.
In my application, I am creating a server, and when a new connection is received, I create a new thread, a new QWebSocket object in it, and connect certain QWebSocket signals to slots defined in the class of the server (the same class where the connection is received and the thread is created).
However, though the thread is created successfully, the slot is being called in the main thread.
Here is a simpler example that simulates what I am doing, an MCVE:
Base.h file:
#ifndef BASE_H
#define BASE_H
#include<QThread>
#include<thread>
#include<QObject>
#include "emitcaller.h"
#include <QDebug>
class Base : public QObject
{
Q_OBJECT
public:
EmitCaller *emitCaller;
void create_thread();
void make_emit();
public slots:
void do_something();
};
#endif // BASE_H
This represents the server class. create_thread() is like the function when a new connection from a client is to be done. do_something() is the slot that needs to be executed when the QWebSocket receives a signal.
Base.cpp file:
#include "base.h"
#include "emitcaller.h"
#include<QEventLoop>
#include <mutex>
#include <condition_variable>
void Base::create_thread()
{
std::mutex mutex;
std::condition_variable cv;
std::thread t = std::thread([&](){
EmitCaller *ec = new EmitCaller;
this->emitCaller = ec;
qDebug() << "thread created, now in thread " << QThread::currentThread();
QObject::connect(ec,SIGNAL(my_signal()),this,SLOT(do_something()),Qt::DirectConnection);
cv.notify_all();
QEventLoop loop;
loop.exec();
});
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock); //wait till connect() completes, so that signal sent is received after that
t.detach();
}
void Base::do_something()
{
qDebug() << "doing something in thread " << QThread::currentThread();
}
void Base::make_emit()
{
qDebug() << "called make_emit in thread " << QThread::currentThread();
emitCaller->do_emit();
}
Next, EmitCaller.h file:
#ifndef EMITCALLER_H
#define EMITCALLER_H
#include <QObject>
#include <QDebug>
class EmitCaller : public QObject
{
Q_OBJECT
public:
void do_emit();
signals:
void my_signal();
};
#endif // EMITCALLER_H
This is to simulate the QWebSocket. The my_signal() signal is the one that the QWebSocket in the program receives to call the do_something() slot. make_emit() is an extra function, just to ask the signal to be emitted, created only for the sake of this simplified example.
EmitCaller.cpp file:
#include "emitcaller.h"
void EmitCaller::do_emit()
{
emit my_signal();
}
main.cpp file:
#include <QApplication>
#include "base.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Base b;
qDebug() << "main in thread " << QThread::currentThread();
b.create_thread();
b.make_emit();
return a.exec();
}
The output is as follows:
main in thread QThread(0xc20180)
thread created, now in thread QThread(0x7fb9680009e0)
called make_emit in thread QThread(0xc20180)
doing something in thread QThread(0xc20180)
Now, as per my understanding, the following happens:
create_thread() is called. The EmitCaller object (QWebSocket object) is created inside a new thread. Thus, the thread affinity of the object should be the new thread, and all signals sent from it should be from the new thread.
connect() is done using Qt::DirectConnection. So, the slot do_something() should be called in this new thread, even though its class object, b, lies in the main thread.
do_emit() is called on the object whose thread affinity is with the new thread, which should result in the behaviour expected as described above.
I expect the output to instead be:
main in thread QThread(0xc20180)
thread created, now in thread QThread(0x7fb9680009e0)
called make_emit in thread QThread(0xc20180)
doing something in thread QThread(0x7fb9680009e0)
A few additional points:
In my server program, I don't have a pointer pointing to the QWebSocket object. However, the signal there is generated when a new client connects. To send the signal myself, I have created a pointer to access the object.
I need to use std::thread, I cannot use QThread for this.
Why is the slot being called in the receiver's thread, instead of the
emitter's thread, even though Qt::DirectConnection is used?
If this is incorrect, where am I going wrong? (I am new to the signal-slot system of Qt).
If this cannot be done this way, how can I achieve the behaviour I want? I would like do_something() to run in a separate thread.
Thank you.
You have to consider 3 threads in your problem statement:
The thread the receiver lives in
The thread the sender lives in
The thread that is emitting the signal
Queued/BlockingQueued connections ensure that the slot will be executed in the receivers thread.
DirectConnection executes the slot in the current thread. This is not always the thread the sender lives in! In fact, there is no standard way to enforce running a slot in the sender's thread (because usually, the receiver's thread is what you want).
NB: AutoConnection uses QueuedConnection if the current thread and receiver thread are not the same, otherwise DirectConnection
To solve your problem, you could forcably switch to the sender's thread if you're on another thread, like this:
In EmitCaller, add
private: Q_INVOKABLE my_thread_do_emit() { do_emit(); }
Then in the implemetation:
void EmitCaller::do_emit()
{
if (this->thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "my_thread_do_emit", Qt::BlockingQueuedConnection);
} else {
emit my_signal();
}
}
However, I would suggest that you reconsider your design. It seems unusual to call a slot in a certain foreign thread. Maybe there is a problem in your thread affinity setup... (e.g. the receiver should live in the newly created thread)

Solving run-time problems with QT threads

My current problem is with two QT threads. One of them emits a signal for starting an operation in the second thread, and afterwards wait for the result. As soon as the second thread finishes, the first thread should continue with its own operation using results from the second thread.
For letting the first thread sleep I use a QMutex and a QWaitCondition. The first thread emits a signal, and afterwards sleeps at the wait condition. But the problem is now: If the second thread somehow managed to be faster than the first thread, and emits the wakeAll()-call before the first thread enters the wait-condition, I get stuck. I could implement a waiting time, but then I am unflexible again, and if the second threads needs more time than the first thread is waiting, I have a problem again.
This problem has already been addressed here: http://woboq.com/blog/qwaitcondition-solving-unavoidable-race.html, but they decided to leave this problem unsolved. So, is there a possibility to avoid this race-condition?
Addition: I don't want to convert this function into a function of the first thread, because this specific function should be accessable from several threads at once without leading to a race condition. I.e. Thread1 should call the function in Thread2, wait til it is finished, Thread3 also wants to call the function, but is not allowed to do that, it has to wait till finish, too. If the function has finished, Thread3 can access it. (Same goes for more than only two threads).
Example function:
This function should emit the signal and afterwards wait for the wake signal:
void Spectrometer_Control::moveStepper(int steps, bool dir)
{
emit stepperMoving();
qDebug() << "From Spectrometer_Control: Stepper should move in direction " + QString::number(dir) + " from position " + QString::number(MonoPos);
int newTarget = MonoPos + ((dir == true)?(steps):(-1 * steps));
qDebug() << "New target: " + QString::number(newTarget);
emit moveStepperToTarget(steps, dir);
qDebug() << "Locking WaitMutex!";
WaitMutex->lock();
qDebug() << "Waiting for signal!";
WaitForEngine->wait(WaitMutex);
WaitMutex->unlock();
qDebug() << "Finally unlocked!";
}
And this function receives the call, and should wake every waiting function up:
void Stepper_Control_Worker::moveStepper(int steps, bool dir)
{
waitMutex->lock();
qDebug() << "Motor moved from down below!";
Stepper_Control_Worker::STP[1]->setValue((dir == true)?BlackLib::high:BlackLib::low);
usleep(50000);
Stepper_Control_Worker::STP[0]->setValue(BlackLib::low);
usleep(50000);
for(int i = 0; i < steps; i++)
{
Stepper_Control_Worker::STP[0]->setValue(BlackLib::high);
usleep(50000);
Stepper_Control_Worker::STP[0]->setValue(BlackLib::low);
}
WaitCond->wakeAll();
waitMutex->unlock();
emit StepperMoved(steps, dir);
}
The second function is a sub-member (not directly, but can only accessed via) of the class "stepper_control". The stepper-controller outer controls can be used by several functions, not only the function moveStepper from Spectrometer_Control, but for making things easier I only added one external function. But after I don't want to get my stepper confused, I wanted to restrict the access as described above.
It's probably safe to let the second thread send a signal back and move the code post wait to that slot.
class Worker1: public QObject{
Q_OBJECT
//...
signals:
void startWorking();
slots:
void answer(QVariant);
};
class Worker2: public QObject{
Q_OBJECT
//...
slots:
void startWorking();
signals:
void answer(QVariant);
};
Otherwise you need to have a variable that the second thread sets while holding the QMutex to signal the first:
thread1:
emit startWorking();
{
QMutexLocker lock(&thread2->mutex);
while(!thread2->finished){//loop guards against spurious wakeups
thread2->cond->wait(&mutex);
}
}
and thread2:
{
QMutexLocker lock(&mutex);
finished=true;
cond->wakeAll();
}
That way if thread2 is faster then thread2->finished is already true by the time thread1 arrives and the mutex protects the variable between testing it and waiting on the QWaitCondition.
Maybe Qt::BlockingQueuedConnection is what you need?
a blocking queued connection is like a queued connection, but the sender thread blocks until the event is picked up by the event loop of the thread the receiver is living in, the slot is invoked, and it returns;