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. multiple thread with QNetworkAccessManager

multiple thread with QNetworkAccessManager

Scheduled Pinned Locked Moved Unsolved General and Desktop
19 Posts 3 Posters 6.4k Views
  • 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.
  • SGaistS SGaist

    It will depend on your architecture. You can have your worker object query a "task list" to get a job. Or have a "task manager" that will generate the workers as needed and give them the tasks they should do.

    VolebabV Offline
    VolebabV Offline
    Volebab
    wrote on last edited by
    #9

    @SGaist Is there an example, I don't know how to do this.

    kshegunovK 1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #10

      Which part ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      VolebabV 1 Reply Last reply
      0
      • VolebabV Volebab

        @SGaist Is there an example, I don't know how to do this.

        kshegunovK Offline
        kshegunovK Offline
        kshegunov
        Moderators
        wrote on last edited by kshegunov
        #11

        @Volebab
        Here's how a worker object is defined and used (barebone code only):

        class MyWorkerObject : public QObject
        {
            Q_OBJECT
        
        public:
            WorkerObject()
                : QObject(NULL), nam(NULL)
            {
            }
        
            ~WorkerObject()
            {
                delete nam;
            }
        
        public slots:
            void initialize()
            {
                nam = new QNetworkAccessManager;
            }
        
            void sendRequest()
            {
                // Send your requests here (connect to the proper controlling signal)
            }
        
           QNetworkAccessManager * nam;
        };
        

        Which you use like this:

        QThread * workerThread = new QThread();
        
        MyWorkerObject * workerObject = new MyWorkerObject;
        workerObject->moveToThread(workerThread);
        
        QObject::connect(workerThread, SIGNAL(started()), workerObject, SLOT(initialize()));
        QObject::connect(workerThread, SIGNAL(finished()), workerObject, SLOT(deleteLater()));
        QObject::connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
        QObject::connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), workerThread, SLOT(quit()));
        
        workerThread->start();
        // Connect the appropriate signal(s) to MyWorkerObject::sendRequest
        

        PS.
        I should really sit down and write a threading tutorial for the wiki ...

        Read and abide by the Qt Code of Conduct

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #12

          @kshegunov In the absolute, there's already an example in QThread's documentation but improvement to the doc/examples are always a good idea :)

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          kshegunovK 1 Reply Last reply
          0
          • SGaistS SGaist

            Which part ?

            VolebabV Offline
            VolebabV Offline
            Volebab
            wrote on last edited by Volebab
            #13

            I will try to explain it better:

            I have a file with 10000 item, each line is a complete name of a person, like: "Johnnie Doe". We have an intranet with an api that we can make a request, example: http://192.168.182.10/user.php?name=Johnnie Doe and it will return a json with a valid property that specify if the costumer is validated or not in the system, along with other information about she/him, like name, documents and so on. The things that I want to do is:

            • How and if is possible to read a big file with thousands of lines into a list without crashing or making the software slow?
            • How to use multiple threads (which I can specify how many) in order to speed up the process of connecting with the intranet api.
            • How to get the result in json of each thread and put in a table with only the name of the costumer and the result of the valid property. For example: I made a consult for the costumer "Johnnie Doe" and he is validated, so I want to put in a table his name and true for the validation.
            • How to make each thread get items on the list without making a mess, for example, I have 5 threads getting items from the list, isn't it going to get messy? How to make each one get an item from the list without problems?

            I work in a company and I have to do this mostly manually and I want to automate that, it's a pain.

            @kshegunov - Thank you for the example.

            kshegunovK 1 Reply Last reply
            0
            • SGaistS SGaist

              @kshegunov In the absolute, there's already an example in QThread's documentation but improvement to the doc/examples are always a good idea :)

              kshegunovK Offline
              kshegunovK Offline
              kshegunov
              Moderators
              wrote on last edited by kshegunov
              #14

              @SGaist
              I suppose so, but this code I can write in my sleep. I can't seem to remember the number of times I've written it here. Also the documentation doesn't really cover some finer points like actually waiting for the thread to finish, or running a loop through the event loop (although this should be simple to gather by yourself if you understand how the API works in the first place).

              Read and abide by the Qt Code of Conduct

              1 Reply Last reply
              0
              • VolebabV Volebab

                I will try to explain it better:

                I have a file with 10000 item, each line is a complete name of a person, like: "Johnnie Doe". We have an intranet with an api that we can make a request, example: http://192.168.182.10/user.php?name=Johnnie Doe and it will return a json with a valid property that specify if the costumer is validated or not in the system, along with other information about she/him, like name, documents and so on. The things that I want to do is:

                • How and if is possible to read a big file with thousands of lines into a list without crashing or making the software slow?
                • How to use multiple threads (which I can specify how many) in order to speed up the process of connecting with the intranet api.
                • How to get the result in json of each thread and put in a table with only the name of the costumer and the result of the valid property. For example: I made a consult for the costumer "Johnnie Doe" and he is validated, so I want to put in a table his name and true for the validation.
                • How to make each thread get items on the list without making a mess, for example, I have 5 threads getting items from the list, isn't it going to get messy? How to make each one get an item from the list without problems?

                I work in a company and I have to do this mostly manually and I want to automate that, it's a pain.

                @kshegunov - Thank you for the example.

                kshegunovK Offline
                kshegunovK Offline
                kshegunov
                Moderators
                wrote on last edited by kshegunov
                #15

                @Volebab said:

                How and if is possible to read a big file with thousands of lines into a list without crashing or making the software slow?

                You put the reading of the file and the heavy lifting in (a) worker object's slot(s) (like above). You control the worker object through signals (that are connected to its slots). The worker object notifies the GUI (or main thread) again by raising signals, which you connect to slots in the widgets.

                How to use multiple threads (which I can specify how many) in order to speed up the process of connecting with the intranet api.

                As already discussed, use one thread for the file reading, leave the network access manager to thread the network requests itself. Use the asynchronous API of the NAM, so you don't block your worker thread (it emits signals when a reply was received, connect those to slots in your worker object).

                How to get the result in json of each thread and put in a table with only the name of the costumer and the result of the valid property. For example: I made a consult for the costumer "Johnnie Doe" and he is validated, so I want to put in a table his name and true for the validation.

                If talking about a table widget (GUI) then emit a signal from the worker object with the customer's information and connect that signal to a slot in the widget/controller object that will add it to the UI.

                How to make each thread get items on the list without making a mess, for example, I have 5 threads getting items from the list, isn't it going to get messy? How to make each one get an item from the list without problems?

                You are thinking even lower level. With multiple threads accessing the same data you need to protect that data. The most basic thing to do in that situation is to have a thread safe queue (which is done with a help of a mutual exclusion lock QMutex and a semaphore QSemaphore) but really, this is low-level stuff that requires experience. If you limit your threads and objects to communicate through signals and slots you don't need to worry about that.

                Kind regards.

                Read and abide by the Qt Code of Conduct

                VolebabV 1 Reply Last reply
                1
                • kshegunovK kshegunov

                  @Volebab said:

                  How and if is possible to read a big file with thousands of lines into a list without crashing or making the software slow?

                  You put the reading of the file and the heavy lifting in (a) worker object's slot(s) (like above). You control the worker object through signals (that are connected to its slots). The worker object notifies the GUI (or main thread) again by raising signals, which you connect to slots in the widgets.

                  How to use multiple threads (which I can specify how many) in order to speed up the process of connecting with the intranet api.

                  As already discussed, use one thread for the file reading, leave the network access manager to thread the network requests itself. Use the asynchronous API of the NAM, so you don't block your worker thread (it emits signals when a reply was received, connect those to slots in your worker object).

                  How to get the result in json of each thread and put in a table with only the name of the costumer and the result of the valid property. For example: I made a consult for the costumer "Johnnie Doe" and he is validated, so I want to put in a table his name and true for the validation.

                  If talking about a table widget (GUI) then emit a signal from the worker object with the customer's information and connect that signal to a slot in the widget/controller object that will add it to the UI.

                  How to make each thread get items on the list without making a mess, for example, I have 5 threads getting items from the list, isn't it going to get messy? How to make each one get an item from the list without problems?

                  You are thinking even lower level. With multiple threads accessing the same data you need to protect that data. The most basic thing to do in that situation is to have a thread safe queue (which is done with a help of a mutual exclusion lock QMutex and a semaphore QSemaphore) but really, this is low-level stuff that requires experience. If you limit your threads and objects to communicate through signals and slots you don't need to worry about that.

                  Kind regards.

                  VolebabV Offline
                  VolebabV Offline
                  Volebab
                  wrote on last edited by Volebab
                  #16

                  @kshegunov

                  Amazing answer and I get most of what you said, the only thing though that I have no idea how to accomplish is:

                  You are thinking even lower level. With multiple threads accessing the same data you need to protect that data. The most basic thing to do in that situation is to have a thread safe queue (which is done with a help of a mutual exclusion lock QMutex and a semaphore QSemaphore) but really, this is low-level stuff that requires experience. If you limit your threads and objects to communicate through signals and slots you don't need to worry about that.

                  I have a QListWidget full of names, a QTableWidget to put informations, I have a worker to read the big file and put each line as the QListWidget item, and I have a worker using QNetworkAccessManager to connect with the API.
                  The thing now is: How the worker using QNetworkAccessManager gets the item from the QListWidget without collapsing with other worker getting at the same time?

                  I know that it might be ask too much, but if you provide me an example I would be really happy. I really need to get this working so I can ease my job here on the company.

                  kshegunovK 1 Reply Last reply
                  0
                  • VolebabV Volebab

                    @kshegunov

                    Amazing answer and I get most of what you said, the only thing though that I have no idea how to accomplish is:

                    You are thinking even lower level. With multiple threads accessing the same data you need to protect that data. The most basic thing to do in that situation is to have a thread safe queue (which is done with a help of a mutual exclusion lock QMutex and a semaphore QSemaphore) but really, this is low-level stuff that requires experience. If you limit your threads and objects to communicate through signals and slots you don't need to worry about that.

                    I have a QListWidget full of names, a QTableWidget to put informations, I have a worker to read the big file and put each line as the QListWidget item, and I have a worker using QNetworkAccessManager to connect with the API.
                    The thing now is: How the worker using QNetworkAccessManager gets the item from the QListWidget without collapsing with other worker getting at the same time?

                    I know that it might be ask too much, but if you provide me an example I would be really happy. I really need to get this working so I can ease my job here on the company.

                    kshegunovK Offline
                    kshegunovK Offline
                    kshegunov
                    Moderators
                    wrote on last edited by kshegunov
                    #17

                    @Volebab
                    Aha! Well that's a bit counter-intuitive indeed. The worker can emit a signal that it can process data (send request or w/e). The GUI is subscribed to that signal and in the slot that handles it, it raises it's own signal with the data. The signal that GUI emits is connected to the worker and the worker gets its data. It sounds like a rollercoaster, but is actually quite simple. Something like this (again bare-bone code only):

                    class MyWorker : public QObject
                    {
                        Q_OBJECT
                    
                    signals:
                        void canProcessData();
                    
                    public slots:
                        void process(MyDataContainer data)
                        {
                            // Send requests w/e
                    
                           // If you want to repeat, emit canProcessData() at the end
                        }
                    };
                    
                    class GuiClass : public QObject // Can be widget or QObject, depending on the exact architecture of your application
                    {
                        Q_OBJECT
                    
                    signals:
                        void startDataProcessing();  // This will start the data processing
                        void dataToProcess(MyDataContainer data);
                    
                    public slots:
                        void dataRequested()
                        {
                            MyDataContainer data; // Collect the data from the GUI side
                    
                            // After collecting the data emit the appropriate signal
                            emit dataToProcess(data);
                        }
                    };
                    

                    You connect those signals in a loop between the two objects:

                    // These two are only for completeness, you have to adjust the pointers so they are referencing the correct objects
                    MyWorker * worker;
                    GuiClass * gui;
                    
                    QObject::connect(gui, SIGNAL(startDataProcessing()), worker, SIGNAL(canProcessData()));  // Delegating the signal so you can start the loop
                    QObject::connect(worker, SIGNAL(canProcessData()), gui, SLOT(dataRequested()));  // The worker requests a new batch of data
                    QObject::connect(gui, SIGNAL(dataToProcess(MyDataContainer)), worker, SLOT(dataToProcess(MyDataContainer)));  // The GUI provides new data for the worker
                    

                    This is how you can "pull" data (as opposed to the usual "push") from another thread.



                    If you have two workers, you can connect one directly to the other. Suppose readWorker is the worker object that reads the data, netWorker is the one making the requests, and gui is the GUI class. The power of the signal-slot mechanism should become obvious here:

                    class ReadWorker : public QObject
                    {
                        Q_OBJECT
                    
                    signals:
                        void haveCustomerName(CustomerName);
                    
                    public slots:
                        void startReading()
                        {
                            // Read the file, for each set of customer name emit the signal
                            while ( /*... reading the file ... */)  {
                                CustomerName name;   // You get a customer from the file
                                emit haveCustomerName(name);
                            }
                        }
                    };
                    
                    class NetworkWorker : public QObject
                    {
                         Q_OBJECT
                    
                    signals:
                         void haveCustomerData(CustomerData);
                    
                    public slots:
                         void getCustomerData(CustomerName name)
                         {
                              // Make the network request, connect other signals if need etc.
                              // At the end of the day, this slot should emit haveCustomerData when it has received it from the network
                         }
                    };
                    
                    class GuiClass : public QObject // Can be widget or QObject, depending on the exact architecture of your application
                    {
                        Q_OBJECT
                    
                    signals:
                        void start();  // This will start the data processing (i.e. reading the file and sending requests)
                    
                    public slots:
                        void onNewCustomerName(CustomerName name)
                       {
                            // This will give you the customer name while waiting for response from the network. You can use it to pre-populate the GUI
                       }
                        void onNewCustomerData(CustomerData data)
                        {
                             // The data had arrived and the worker has notified you. Use it to update the GUI
                        }
                    };
                    

                    You can connect those three "in a triangle":

                    // These are only for completeness, you have to adjust the pointers so they are referencing the correct objects
                    ReadWorker * readWorker;
                    NetworkWorker * netWorker;
                    GuiClass * gui;
                    
                    // Starting the reading when the GUI emits start()
                    QObject::connect(gui, SIGNAL(start()), readWorker, SLOT(startReading())); 
                    // One worker notifies the other that a customer name has been read. The network worker can start making requests with that
                    QObject::connect(readWorker, SIGNAL(haveCustomerName(CustomerName)), netWorker, SLOT(getCustomerData(CustomerName))); 
                    // The worker that reads the data also notifies the GUI for the customer name, so the GUI can pre-populate (if it wishes) some widgets or w/e
                    QObject::connect(readWorker, SIGNAL(haveCustomerName(CustomerName)), gui, SLOT(onNewCustomerName(CustomerName))); 
                    // The worker that handles the network notifies the GUI that customer data is available, GUI should then update itself to reflect that.
                    QObject::connect(netWorker, SIGNAL(haveCustomerData(CustomerData)), gui, SLOT(onNewCustomerData(CustomerData))); 
                    

                    Well, it turned out a bit long-ish than I intended initially ... anyway, I think this should help.
                    Kind regards.

                    Read and abide by the Qt Code of Conduct

                    VolebabV 1 Reply Last reply
                    1
                    • kshegunovK kshegunov

                      @Volebab
                      Aha! Well that's a bit counter-intuitive indeed. The worker can emit a signal that it can process data (send request or w/e). The GUI is subscribed to that signal and in the slot that handles it, it raises it's own signal with the data. The signal that GUI emits is connected to the worker and the worker gets its data. It sounds like a rollercoaster, but is actually quite simple. Something like this (again bare-bone code only):

                      class MyWorker : public QObject
                      {
                          Q_OBJECT
                      
                      signals:
                          void canProcessData();
                      
                      public slots:
                          void process(MyDataContainer data)
                          {
                              // Send requests w/e
                      
                             // If you want to repeat, emit canProcessData() at the end
                          }
                      };
                      
                      class GuiClass : public QObject // Can be widget or QObject, depending on the exact architecture of your application
                      {
                          Q_OBJECT
                      
                      signals:
                          void startDataProcessing();  // This will start the data processing
                          void dataToProcess(MyDataContainer data);
                      
                      public slots:
                          void dataRequested()
                          {
                              MyDataContainer data; // Collect the data from the GUI side
                      
                              // After collecting the data emit the appropriate signal
                              emit dataToProcess(data);
                          }
                      };
                      

                      You connect those signals in a loop between the two objects:

                      // These two are only for completeness, you have to adjust the pointers so they are referencing the correct objects
                      MyWorker * worker;
                      GuiClass * gui;
                      
                      QObject::connect(gui, SIGNAL(startDataProcessing()), worker, SIGNAL(canProcessData()));  // Delegating the signal so you can start the loop
                      QObject::connect(worker, SIGNAL(canProcessData()), gui, SLOT(dataRequested()));  // The worker requests a new batch of data
                      QObject::connect(gui, SIGNAL(dataToProcess(MyDataContainer)), worker, SLOT(dataToProcess(MyDataContainer)));  // The GUI provides new data for the worker
                      

                      This is how you can "pull" data (as opposed to the usual "push") from another thread.



                      If you have two workers, you can connect one directly to the other. Suppose readWorker is the worker object that reads the data, netWorker is the one making the requests, and gui is the GUI class. The power of the signal-slot mechanism should become obvious here:

                      class ReadWorker : public QObject
                      {
                          Q_OBJECT
                      
                      signals:
                          void haveCustomerName(CustomerName);
                      
                      public slots:
                          void startReading()
                          {
                              // Read the file, for each set of customer name emit the signal
                              while ( /*... reading the file ... */)  {
                                  CustomerName name;   // You get a customer from the file
                                  emit haveCustomerName(name);
                              }
                          }
                      };
                      
                      class NetworkWorker : public QObject
                      {
                           Q_OBJECT
                      
                      signals:
                           void haveCustomerData(CustomerData);
                      
                      public slots:
                           void getCustomerData(CustomerName name)
                           {
                                // Make the network request, connect other signals if need etc.
                                // At the end of the day, this slot should emit haveCustomerData when it has received it from the network
                           }
                      };
                      
                      class GuiClass : public QObject // Can be widget or QObject, depending on the exact architecture of your application
                      {
                          Q_OBJECT
                      
                      signals:
                          void start();  // This will start the data processing (i.e. reading the file and sending requests)
                      
                      public slots:
                          void onNewCustomerName(CustomerName name)
                         {
                              // This will give you the customer name while waiting for response from the network. You can use it to pre-populate the GUI
                         }
                          void onNewCustomerData(CustomerData data)
                          {
                               // The data had arrived and the worker has notified you. Use it to update the GUI
                          }
                      };
                      

                      You can connect those three "in a triangle":

                      // These are only for completeness, you have to adjust the pointers so they are referencing the correct objects
                      ReadWorker * readWorker;
                      NetworkWorker * netWorker;
                      GuiClass * gui;
                      
                      // Starting the reading when the GUI emits start()
                      QObject::connect(gui, SIGNAL(start()), readWorker, SLOT(startReading())); 
                      // One worker notifies the other that a customer name has been read. The network worker can start making requests with that
                      QObject::connect(readWorker, SIGNAL(haveCustomerName(CustomerName)), netWorker, SLOT(getCustomerData(CustomerName))); 
                      // The worker that reads the data also notifies the GUI for the customer name, so the GUI can pre-populate (if it wishes) some widgets or w/e
                      QObject::connect(readWorker, SIGNAL(haveCustomerName(CustomerName)), gui, SLOT(onNewCustomerName(CustomerName))); 
                      // The worker that handles the network notifies the GUI that customer data is available, GUI should then update itself to reflect that.
                      QObject::connect(netWorker, SIGNAL(haveCustomerData(CustomerData)), gui, SLOT(onNewCustomerData(CustomerData))); 
                      

                      Well, it turned out a bit long-ish than I intended initially ... anyway, I think this should help.
                      Kind regards.

                      VolebabV Offline
                      VolebabV Offline
                      Volebab
                      wrote on last edited by
                      #18

                      @kshegunov What is the propose of the GuiClass and MyDataContainer classes? I mean, I have QMainWindow, isn't it already a gui class? And Why MyDataContainer if I will be reading using the ReadWorker?

                      kshegunovK 1 Reply Last reply
                      0
                      • VolebabV Volebab

                        @kshegunov What is the propose of the GuiClass and MyDataContainer classes? I mean, I have QMainWindow, isn't it already a gui class? And Why MyDataContainer if I will be reading using the ReadWorker?

                        kshegunovK Offline
                        kshegunovK Offline
                        kshegunov
                        Moderators
                        wrote on last edited by
                        #19

                        @Volebab

                        What is the propose of the GuiClass and MyDataContainer classes?

                        GuiClass is a name for the class managing the user interface. It can be a QObject, or a MainWindow subclass or practically anything that has a QObject ancestor. If you have derived from QMainWindow, which is the usual approach, then GuiClass is exactly your main window class.

                        MyDataContainer, again is a generic name I'd chosen when writing the example. It's the class that contains the data (whence the name) to be transferred between the threads. As you can see there are no declarations for it, it can be QVector, QImage, QString or some integral type as int. It can also be a complex user-defined type (a structure or a class, but then some registrations are needed).

                        I mean, I have QMainWindow, isn't it already a gui class?

                        It is and you can use that instead of GuiClass.

                        And Why MyDataContainer if I will be reading using the ReadWorker?

                        So you can transfer the data safely between the threads.
                        If you give access directly (that is you don't use signals and slots) to an object's method/property then you have to put locks for each method call and/or property access that might happen from two threads.

                        Kind regards.

                        Read and abide by the Qt Code of Conduct

                        1 Reply Last reply
                        0

                        • Login

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