How to ensure all connected classes react to the signal from different threads in the same order?
-
Hi, so I made a small PoC where I connected two classes A and B to the third one C (they all live in the same main thread). I made C launch a bunch of threads that continuously emit signals with a number from 1 to 1000 from the FOR loop (threads are not synchronized). Then I compared the A's and B's arrays of received signals. The order of received signals wasn't aligned. So in order to ensure that all classes will receive signals in the same order should I just add synchronization to the C's emit?
The code for better understanding:// a.h class A : public QObject { Q_OBJECT public: explicit A(QObject* parent) : QObject(parent) { } public slots: void reactToSignal(int number) { // simulate work std::this_thread::sleep_for(std::chrono::milliseconds(10)); m_nums.push_back(number); } public: std::vector<int> m_nums; };
//b.h is the same as a.h
// c.h class C : public QObject { Q_OBJECT public: explicit C(QObject *parent = nullptr) : QObject(parent) { } ~C() { for(std::thread& worker : m_threads) { if(worker.joinable()) worker.join(); } } void StartWorking() { int size = 4; for(int i = 0; i < size; i++) { m_threads.emplace_back(std::thread(std::bind(&C::Work, this))); } m_isReady = true; m_cv.notify_all(); } signals: void statusChanged(int); private: void Work() { { std::shared_lock<std::shared_mutex> lock(m_mutex); m_cv.wait(lock,[this]{return m_isReady;}); } for(int i = 1; i <= 1000; i++) { emit statusChanged(i); std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } private: bool m_isReady = false; std::condition_variable_any m_cv; std::shared_mutex m_mutex; std::vector<std::thread> m_threads; };
Then I just connect them like that in main window:
m_a = new A(this); m_b = new B(this); m_c = new C(this); isConnected = isConnected && connect(m_c, SIGNAL(statusChanged(int)), m_a, SLOT(reactToSignal(int))); isConnected = isConnected && connect(m_c, SIGNAL(statusChanged(int)), m_b, SLOT(reactToSignal(int))); m_c->StartWorking();
When I compare A's and B's m_nums vectors, they don't align (in most cases), which means signals were processed in different times for A and B. How to ensure that each signal is processed in the same order for A and B?
-
@AlexpoUA
Would you not be better/simpler/quicker to place just a single slot on the signal and have that (directly) call whatever in classes A, B, ... , so now you receive one signal in one slot rather than separateconnect()
s?Note that being across threads you still do not what order signals arrive for slot processing. However, I believe that if a given thread emits signal and then shortly afterward emits the same signal again then they will arrive in that order for the slot calls. Unless an expert says even that is not guaranteed?
Otherwise as you say you will have to put in some sort of synchronisation. Which would seem like it spoils the point of using threads.
-
@AlexpoUA said in How to ensure all connected classes react to the signal from different threads in the same order?:
The order of received signals wasn't aligned
What does this mean?
-
There is no order as soon as there are different threads involved - how should this work? How to you want to handle which thread is executed first by the os?
-
@Christian-Ehrlicher What I want is to make classes connected to statusChanged(int number) receive the numbers in the same order, example:
thread1 emits statusChanged(1)
thread2 emits statusChanged(1)
thread3 emits statusChanged(1)
thread1 emits statusChanged(2)
thread2 emits statusChanged(2)// there is no order in which threads emit signals, it's ok
// signals are then transformed into events and are added to the main thread's event loop. I want to achieve the following:If A receives signals in order of 1,1,1,2,2 I want B to also receive them in such order.
A may receive them in order of 1,1,2,1,2, and again I want B to receive those signals in the same order.
Should I just synchronize access to emit in C? -
@AlexpoUA
Would you not be better/simpler/quicker to place just a single slot on the signal and have that (directly) call whatever in classes A, B, ... , so now you receive one signal in one slot rather than separateconnect()
s?Note that being across threads you still do not what order signals arrive for slot processing. However, I believe that if a given thread emits signal and then shortly afterward emits the same signal again then they will arrive in that order for the slot calls. Unless an expert says even that is not guaranteed?
Otherwise as you say you will have to put in some sort of synchronisation. Which would seem like it spoils the point of using threads.
-