Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to force a thread waiting for signal
Forum Updated to NodeBB v4.3 + New Features

How to force a thread waiting for signal

Scheduled Pinned Locked Moved Unsolved General and Desktop
21 Posts 3 Posters 6.0k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • dualD Offline
    dualD Offline
    dual
    wrote on last edited by
    #1

    Hello everyone, I have a client-server application. The server side generates a thread that has to wait for readyRead from client in order to receive Json and Files from the client (it's a remote backup application).
    Obviously thread closes while waiting for readyread, because it has nothing else to do.
    How can I force it to wait the signal? Possibly avoiding busy-waiting

    I tried using waitForReadyRead but the main problem is that the signal is not reemitted when calling the function within a slot connected to the readyRead signal.

    Can emitting user-defined signals in order to bypass the waitForReadyRead's limitations be a possible solution?
    Something like this:

    connect(this, &sharing::mySignal, this, &sharing::readFile);
    void sharing::readFile() {
    /*
    Reading a block of the file...
    */
    clientConnection->waitForReadyRead();
    emit mySign();
    }

    Any idea?

    1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      First you can create the thread after you completely red the json and a second option is to emit a signal once the json is ready and connect it to a slot in your thread.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      1 Reply Last reply
      3
      • dualD Offline
        dualD Offline
        dual
        wrote on last edited by
        #3

        Thanks for answering but I don't think that your proposals can be suitable for my situation: the thread receives an undefined number of communications from client, so it has to keep listen until the client doesn't shut the connection down.

        1 Reply Last reply
        0
        • Christian EhrlicherC Offline
          Christian EhrlicherC Offline
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @dual said in How to force a thread waiting for signal:

          the thread receives an undefined number of communications from client,

          What do you mean with this?

          You have a client connection receiving data. Once the data was successfully received send it to your worker thread and let it do the work. Where's the problem?

          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
          Visit the Qt Academy at https://academy.qt.io/catalog

          dualD 1 Reply Last reply
          0
          • Christian EhrlicherC Christian Ehrlicher

            @dual said in How to force a thread waiting for signal:

            the thread receives an undefined number of communications from client,

            What do you mean with this?

            You have a client connection receiving data. Once the data was successfully received send it to your worker thread and let it do the work. Where's the problem?

            dualD Offline
            dualD Offline
            dual
            wrote on last edited by dual
            #5

            @Christian-Ehrlicher Server has to manage multiple clients, let me explain the whole architecture: I have a server (with its qTcpServer) that waits for incoming connections. When a connection is found, a thread is generated and a socketDescriptor is passed. This new thread will exchange data with the client, until the client closes the connection. For this reason I cannot receive the data in the main thread, because I have to manage multiple connections at the same time

            1 Reply Last reply
            0
            • Christian EhrlicherC Offline
              Christian EhrlicherC Offline
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on last edited by
              #6

              And where do you do the actual work? When each connection has an own thread (which is somewhat over-engineered and will not scale well for more than lets say 1k connections) then you can do the calculation inside this thread or start another one once the full data was received.

              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
              Visit the Qt Academy at https://academy.qt.io/catalog

              dualD 1 Reply Last reply
              0
              • Christian EhrlicherC Christian Ehrlicher

                And where do you do the actual work? When each connection has an own thread (which is somewhat over-engineered and will not scale well for more than lets say 1k connections) then you can do the calculation inside this thread or start another one once the full data was received.

                dualD Offline
                dualD Offline
                dual
                wrote on last edited by
                #7

                @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 connection

                So the main problem is that the thread server side must wait with readyRead for json or data without returning

                1 Reply Last reply
                0
                • Christian EhrlicherC Offline
                  Christian EhrlicherC Offline
                  Christian Ehrlicher
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  @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?

                  Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                  Visit the Qt Academy at https://academy.qt.io/catalog

                  dualD 1 Reply Last reply
                  0
                  • Christian EhrlicherC Christian Ehrlicher

                    @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?

                    dualD Offline
                    dualD Offline
                    dual
                    wrote on last edited by
                    #9

                    @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

                    1 Reply Last reply
                    0
                    • Christian EhrlicherC Offline
                      Christian EhrlicherC Offline
                      Christian Ehrlicher
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      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...

                      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                      Visit the Qt Academy at https://academy.qt.io/catalog

                      dualD 1 Reply Last reply
                      3
                      • Christian EhrlicherC Christian Ehrlicher

                        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...

                        dualD Offline
                        dualD Offline
                        dual
                        wrote on last edited by
                        #11

                        @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

                        1 Reply Last reply
                        0
                        • Christian EhrlicherC Offline
                          Christian EhrlicherC Offline
                          Christian Ehrlicher
                          Lifetime Qt Champion
                          wrote on last edited by
                          #12

                          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.

                          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                          Visit the Qt Academy at https://academy.qt.io/catalog

                          1 Reply Last reply
                          4
                          • S Offline
                            S Offline
                            SimonSchroeder
                            wrote on last edited by
                            #13

                            @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 of run() 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.

                            dualD 1 Reply Last reply
                            0
                            • S SimonSchroeder

                              @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 of run() 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.

                              dualD Offline
                              dualD Offline
                              dual
                              wrote on last edited by Christian Ehrlicher
                              #14

                              @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

                              1 Reply Last reply
                              0
                              • Christian EhrlicherC Offline
                                Christian EhrlicherC Offline
                                Christian Ehrlicher
                                Lifetime Qt Champion
                                wrote on last edited by
                                #15

                                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.

                                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                                Visit the Qt Academy at https://academy.qt.io/catalog

                                dualD 1 Reply Last reply
                                1
                                • Christian EhrlicherC Christian Ehrlicher

                                  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.

                                  dualD Offline
                                  dualD Offline
                                  dual
                                  wrote on last edited by dual
                                  #16

                                  @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?

                                  1 Reply Last reply
                                  0
                                  • Christian EhrlicherC Offline
                                    Christian EhrlicherC Offline
                                    Christian Ehrlicher
                                    Lifetime Qt Champion
                                    wrote on last edited by
                                    #17

                                    @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.

                                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                                    Visit the Qt Academy at https://academy.qt.io/catalog

                                    1 Reply Last reply
                                    0
                                    • S Offline
                                      S Offline
                                      SimonSchroeder
                                      wrote on last edited by
                                      #18

                                      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.

                                      dualD 1 Reply Last reply
                                      0
                                      • S SimonSchroeder

                                        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.

                                        dualD Offline
                                        dualD Offline
                                        dual
                                        wrote on last edited by dual
                                        #19

                                        @SimonSchroeder I did some tries but still it doesn't work as expected.

                                        In server.h (that is the main thread object) I defined

                                        class 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 have

                                        sharing::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.

                                        1 Reply Last reply
                                        0
                                        • Christian EhrlicherC Offline
                                          Christian EhrlicherC Offline
                                          Christian Ehrlicher
                                          Lifetime Qt Champion
                                          wrote on last edited by
                                          #20

                                          @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.

                                          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                                          Visit the Qt Academy at https://academy.qt.io/catalog

                                          dualD 1 Reply Last reply
                                          2

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved