Unsolved How to force a thread waiting for signal
-
@Christian-Ehrlicher Since it is a remote backup project, the client will ask the server to store/delete a file.
The usual scenario is:
Client establishes a connection with the server
The server creates a thread to talk with client
The client sends a json to tell the server that it will send a file to store
Server sends ack
Client sends the file
Server receives the file (with multiple readyRead signal) and then stores the file in a directory (same thread will do this work)
Server sends ack to the client
The client can send another json or close the connectionSo the main problem is that the thread server side must wait with readyRead for json or data without returning
-
@dual said in How to force a thread waiting for signal:
So the main problem is that the thread server side must wait with readyRead for json or data without returning
What do you mean with 'wait' here? Where should your thread return to?
-
@Christian-Ehrlicher I'd like to find a good way to let the thread wait for the next json/block-of-file from the client without closing.
With "returning" I mean that the thread will close and return to the main thread.Sorry for my late reply but my reputation is not high enough to post quicker
-
Why should the thread close? Simply let the thread run the event loop and do your stuff via signals and slots as described in the documentation...
-
@Christian-Ehrlicher Actually I'm using std::thread because I'm more confident with the stdlib for threads. I'll try QThread instead, maybe they can exploit my problem
-
There is no difference between std::thread and QThread in your case at all. You need a running event loop to process Qt signals and slots with std::thread and with QThread.
-
@Christian-Ehrlicher Actually, there is a slight difference between std::thread and QThread: If you take a plain QThread object and call
start()
on it, the default implementation ofrun()
will launch an event loop. std::thread does not know about Qt and thus you have to start the event loop yourself.I suggest using QThread to get an event loop.
-
@SimonSchroeder thank you for answering. I tried to use QThread but it closes before receiving readyread signal. This is my implementation:
/* Main thread: */ int sd = tcpServer->nextPendingConnection()->socketDescriptor(); std::cout<<"Socket descriptor: "<<sd<<std::endl; thread = QThread::create([sd]{ sharing s(sd); }); thread->start(); /* class sharing: */ sharing::sharing(int socketDescriptor){ clientConnection = new QTcpSocket; if (!clientConnection->setSocketDescriptor(socketDescriptor)) { std::cout<<"Error on setting Socket Descriptor..."<<std::endl; return; } in.setDevice(clientConnection); in.setVersion(QDataStream::Qt_5_5); connect(clientConnection, &QIODevice::readyRead, this, &sharing::receive); }
sharing is the class in charge of creating the QTcpSocket and of managing the file receiving. After the construction of sharing, I'd expect the thread to wait until readyread is emitted but it dosn't.
/edit: Edited by moderator: Please use the code - tags for better readability
-
As we already told you you need a running event loop in your thread - no matter if it's a QThread or std::thread or whatever. So please start one.
-
@Christian-Ehrlicher What about this sentence?
@SimonSchroeder said in How to force a thread waiting for signal:
If you take a plain QThread object and call start() on it, the default implementation of run() will launch an event loop
Also online i've found that Qthread has a eventLoop on the default
run()
method. This point is not clear to me.
By the way, do you suggest to place a eventLoop in the sharing constructor? -
@dual said in How to force a thread waiting for signal:
This point is not clear to me.
What is not clear? QThread's run method simply executes an eventloop.
By the way, do you suggest to place a eventLoop in the sharing constructor?
No, it should go into the thread's main function.
-
What your last code does is placing only the constructor call into a separate thread. It will not continue running. What you should do is more like this:
QThread *thread = new QThread(); thread->start(); sharing *s = new sharing(sd); s->moveToThread(thread);
I haven't check with the exact syntax, so you need to check if this compiles. Notice that your
sharing
object also needs to be a pointer to outlive the current scope. It also should inherit from QObject so that you can move it to the other thread. Only then will your new thread's event loop handle its slots.You should also think about the lifetime of the thread and sharing objects. You need to delete both when the connection handled by this thread is closed.
-
@SimonSchroeder I did some tries but still it doesn't work as expected.
In
server.h
(that is the main thread object) I definedclass server : public QObject { Q_OBJECT QThread workerThread; private: sharing *worker; void newClient(); }
and in
server.cpp
void server::newClient() { int sd = tcpServer->nextPendingConnection()->socketDescriptor(); std::cout<<"Socket descriptor: "<<sd<<std::endl; if(workerThread.isRunning()){ std::cout<<"thread is running.. my thread id " << std::this_thread::get_id()<<std::endl; } else std::cout<<"thread is not running.."<<std::endl; worker = new sharing(sd); connect(&workerThread, &QThread::started, worker, &sharing::doWork); connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); worker->moveToThread(&workerThread); workerThread.start(); //workerThread.wait(); }
where the if-else part is used as debug in order to check if the thread is still running when a new client tries to connect.
While in
sharing.cpp
I havesharing::sharing(int socketDescriptor):socketDescriptor(socketDescriptor){ } void sharing::doWork(){ std::cout<<"Connecting... "<<std::endl; clientConnection = new QTcpSocket; if (!clientConnection->setSocketDescriptor(socketDescriptor)) { std::cout<<"Error on setting Socket Descriptor..."<<std::endl; return; } in.setDevice(clientConnection); in.setVersion(QDataStream::Qt_5_5); connect(clientConnection, &QIODevice::readyRead, this, &sharing::receive); std::cout<<"Connected "<<std::endl; }
and in
sharing::receive
I have a switch to read json received by the client. Sharing class inherits from QObject.At the moment the code works only if the
workerThread.wait();
is not commented, while sharing will not receive any other readyRead when the newClient function ends. But the thread is still running when I create a new client, so I think that the eventLoop is correctly working.
Of course this code is not good to manage multiple clients, it is just a preliminary version because I want to reach a working version of multi-thread communication between a client and the server. -
@dual said in How to force a thread waiting for signal:
tcpServer->nextPendingConnection()->socketDescriptor();
This is wrong since this already creates a QTcpSocket which is repsonsible for your socket and receives the readyRead signals.
You want to override QTcpServer::incomingConnection() as described in the threaded fortune server example. -
@Christian-Ehrlicher your answer totally solved my problem. Thank you so much.