简体   繁体   中英

Signals and slots between objects in different threads in Qt

Basically, I've the next code:

 class serverTCP : public QObject
 {
      // Other methods...

      signals:
           void newInstructions(QJsonDocument jDoc);

      public slots:
           void responseObtained(QJsonDocument jDoc);
 }

 class gatherModbus : public QObject
 {
      // Other methods...

      signals:
           void responseReady(QJsonDocument jDoc);

      public slots:
           void executeInstruction(QJsonDocument jDoc);
           void myprocess() {
                while(true)
                {
                     // Write and read Serial Port
                     // Save data in json 
                }
           };
 }

 void main(int argc, char *argv[])
 {
      QCoreApplication a(argc, argv);
      int netsNumber = 2; //In reality this is dynamic. It's only a example
      serverTCP *server = new serverTCP;
      gatherModbus * gather = new gatherModbus[netsNumber];
      QThread * threads = new QThread[netsNumber];

      // more necessary code...

      for(int i = 0; i < netsNumber; i++)
      {
           gather[i].moveToThread(threads[i]);

           QObject::connect(&server, SIGNAL(newInstructions(QJsonDocument)),
                            &gather[i], SLOT(executeInstruction(QJsonDocument)));

           QObject::connect(&gather[i], SIGNAL(responseReady(QJsonDocument)),
                            &server, SLOT(responseObtained(QJsonDocument)));

           QObject::connect(&threads[i], SIGNAL(start()), 
                            &gather[i], SLOT(myprocess()));

           // Other signals needed between the objects 'gather' and 'threads'

           threads[i].start();
      }

      a.exec();
 }

The problem is that the connections between objects 'server' and 'gather' do not work. The object 'server' is in the same thread as the 'main' function but objects 'gather' have moved to other threads.

What have I to do to make both objects can communicate properly?

My purpose is that the 'server' must be able to send a signal to all objects 'gather' there are. In each of the objects 'gather' must execute the slot and return the 'server' response if any.

If I set up the connection to be the type Qt::DirectConnection slots running on the same thread as the 'main' function and object 'server' and that does not interest me.

Any help or suggestions will be appreciated.

All is in Qt documentation.
First, read that .
Then if you're not satisfied, you can use QCoreApplication::postEvent() (for more informations you need : here )

Both signals/slots ( QObject:connect() ) and QCoreApplication::postEvent() are thread-safe and can solve your problem.

So events and signal/slots are two parallel mechanisms accomplishing the same things, in general an event will be generated by an outside entity (eg Keyboard, Mouswheel) and will be delivered through the event loop in QApplication. In general unless you set up the code you will not be generating events. You might filter them through QObject::installEventFilter() or handle events in subclassed object by overriding the appropriate functions.

Signals and Slots are much easier to generate and receive and you can connect any two QObject subclasses. They are handled through the Metaclass (have a look at your moc_classname.cpp file for more) but most of the interclass communication that you will produce will probably use signals and slots. Signals can get delivers immediately or deferred via a queue (if you are using threads) A signal can be generated

Your demo code seems OK. That's how we organize our current project. You'd better provide more detailed codes if necessary to explain your problem.

BTW, after reading your interests, I'd recommend you the QtConcurrent module which seems fitting your interest better.

Huh... Your code is not ok. This is the source of all your trouble

void myprocess() {
      while(true)
      {
          // Write and read Serial Port
          // Save data in json 
       }
};

If you want the slots newInstructions and responseObtained slots to ever run, myprocess should not be an infinite loop. You need to :

  • Modify myprocess such that once it is done writing and reading currently available data , it completes
  • Have a mechanism to know that new processing need to be done. For instance, if you are using a QIODevice subclass (socket, input stream, etc...) you have the signal QIODevice::readyRead() which will notify you there is new data to read from the device. I suspect your newInstructions is supposed to do just that.
  • connect this mechanism to another call to myprocess to allow the processing to start again

Edit : Given your comment, this is a way to modify the infinite while loop without too much modification.

void myprocess() {
      make_one_processing_round();
      if(should_continue_processing())
      {
          QMetaObject::invokeMethod(this, &gatherModbus::myprocess, Qt::QueuedConnection);
      }
};

QMetaObject::invokeMethod will schedule this method for execution at the back of the thread QEventLoop queue. Which means other slots can execute.

I can solve my problem adding the next line in the end of "myprocess" method:

QCoreApplication::processEvents(QEventLoop::AllEvents);

The final code of this method is this:

void myprocess() {
            while(true)
            {
                 // Write and read Serial Port
                 // Save data in json 

                 // New line:
                 QCoreApplication::processEvents(QEventLoop::AllEvents);
            }
       };

With this line I get that events will processed if any. I don't known if it is the best solution, but it works as wanted.

Thanks to all of you for your help and answers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM