Search code examples
c++multithreadingqtsignals-slots

QT - force an object to process incoming signals


I am wondering how to tell a QObject to process all signals and call the slots associated with them. Here's the concrete problem I am having, for a better description of the question:

My program consists of three Qthreads : Main, Communication and Input.

The communication thread handles communication via the network, the Input thread handles user input, and both have several signal-slot connections to the main thread. Whenever a network event occurs, or whenever the user inputs a commandline command, a signal from the respective thread is called, which then activates the appropriate connected slot in the main thread. The main thread's role is to process these events. My code looks as follows:

QApplication a(argc, argv);
CommObj co; //inherits from QThread
co.start();  //Starts the thread
InputObj io; //inherits from QThread
io.start(); //Starts the thread
MainObj u(&co,&io);
return a.exec();

Now, what I want to achieve is for the main thread to not reach the last line. My intentions are to call a method run() within the constructor of MainObj which is going to do something along the lines of this:

void run ()
{
 forever
 {
  //process all signals..
 }
}

However, I do not know how to implement the process all signals part. Any advice on how this could be done (including workarounds) would be very welcome.


Solution

  • This is completely unnecessary. a.exec() runs an event loop that will receive and process the events sent by other threads.

    When a slot is invoked due to a signal being emitted in a different thread, Qt is posting a QMetaCallEvent to the receiver object. The QObject::event method is able to re-synthesize the slot call based on the data in the event.

    Thus, you need to do nothing. a.exec() does what you want. Feel free to invoke it from MainObj's constructor, as qApp->exec() or as QEventLoop loop; loop.exec(), but that's rather bad design.

    The real questions are:

    1. Why do you need MainObj's constructor to spin an event loop?

    2. What sort of "user input" are you processing in the io? You can't access any GUI objects from that thread.

    3. Why are you deriving from QThread if you're using Qt's networking? You definitely don't want to do that - it won't work unless you spin an event loop, so you might as well just use a QThread without changes. Well, to be safe, you need just to make the thread destructible, so:

      class Thread {
        using QThread::run; // make it final
      public:
        Thread(QObject * parent = 0) : QThread(parent) {}
        ~Thread() { requestInterruption(); quit(); wait(); }
      };
      

      Anyway, by not using standard QThread that spins an event loop, the communication will be one way. Nothing in such threads will be able to react to signals from other threads.

    You need to rearchitect as follows:

    1. Use the Thread class as above. It's safe to be destructed at any time.

    2. Have worker objects that run asynchronously using signals/slots/timers.

    3. Move constructed workers to their threads.