Consecutive emiting signal not handled by different thread
-
Hi.
I have tied to build multi thread GUI app with TCP communication. This GUI sends and receives data from embedded sytem.
in .h:
@
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();tcp_worker *worker_1; tcp_worker *worker_2;
private:
Ui::MainWindow *ui;QTimer *timer; QThread *thread_1; QThread *thread_2;
@
in cpp:
@
thread_1 = new QThread;
thread_2 = new QThread;worker_1 = new tcp_worker;
worker_2 = new tcp_worker;// Some signal slot connections in there
worker_1->moveToThread(thread_1);
worker_2->moveToThread(thread_2);thread_1->start();
thread_2->start();
@Everything goes perfect up to this point. I can receve and send signal to worker class to organize TCP communication. When I need to emit consecutive emit signal in pushbutton click event, I see that only one emit signal triger the connected slot. I can only overcome this with using empty loop between two emit signal statement. I thing this is required because of tcp_thread to goes event loop after process the emmited signal.
According to my signal slot knowledge, consecutive signals added to evet queue and it will process when the thread reach event loop. I have tried queued and blocking queued connection types as well. How can I overcome that problem without use dummy loop?
Thanks for your help.
example code:
@
void MainWindow::on_opt_button_clicked()
{
emit request_data_front(chanel_data_type);
emit request_data_rear(chanel_data_type);int k = 0; for(int i=0; i<6000000; i++) { k += 1; } emit request_data_front(chanel_number_front); emit request_data_rear(chanel_number_rear);
}
@ -
Hi,
First of all check the QThread documentation. It has several static sleep methods.
I don't see any issues in the code you have shown. You should get each of your slots called twice with or without the busy-waiting for loop.
It would help if you prepared a sample project reproducing your issue and uploaded it somewhere.
-
Hope you are connecting slots with appropriate signals.what is the connect statement. Which object you are connecting ? I suspect some issue with connect statement and destination object.
-
Thanks for reply.
It is hard to imagine the structure when you move the object to created thread. I thing object and thread creation, signal connection, moving to thread and starting thread order is correct. I suspact first connection from thread to worker.
On the other hand, in my situation, when I close the GUI thread, worker thread should be automatically closed, but its not. I am sanding some periodic TCP packets, and it continue to send it after close. I thing it is related to TCP socket structure.
Here is my connect statements related to this subject:
@
// For tcp socket creation (initial statements)
connect(thread_1, SIGNAL(started()), worker_1, SLOT(run()));
connect(thread_2, SIGNAL(started()), worker_2, SLOT(run()));// For connecting specified ip-port
connect(this, SIGNAL(connect_to_card()), worker_1, SLOT(connect_to_card()));
connect(this, SIGNAL(connect_to_card()), worker_2, SLOT(connect_to_card()));// To see coonection status in textbox
connect(worker_1, SIGNAL(set_status(QString)), this, SLOT(write_status(QString)));
connect(worker_2, SIGNAL(set_status(QString)), this, SLOT(write_status(QString)));// To plot incoming ByteArray
connect(worker_1, SIGNAL(read_data(QByteArray, QString)), this, SLOT(plot_data_from_card(QByteArray, QString)), Qt::QueuedConnection);
connect(worker_2, SIGNAL(read_data(QByteArray, QString)), this, SLOT(plot_data_from_card(QByteArray, QString)), Qt::QueuedConnection);// To send command from TCP
connect(this, SIGNAL(request_data_front(QByteArray)), worker_1, SLOT(request_data(QByteArray)), Qt::QueuedConnection);
connect(this, SIGNAL(request_data_rear(QByteArray)), worker_2, SLOT(request_data(QByteArray)), Qt::QueuedConnection);// internal timer connection
connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));// Set start flag in workers
connect(this, SIGNAL(start()), worker_1, SLOT(set_start()));
connect(this, SIGNAL(start()), worker_2, SLOT(set_start()));// Close workers
connect(ui->close_button, SIGNAL(clicked()), worker_1, SLOT(close()));
connect(ui->close_button, SIGNAL(clicked()), worker_2, SLOT(close()));
connect(ui->close_button, SIGNAL(clicked()), this, SLOT(close()));worker_1->moveToThread(thread_1); worker_2->moveToThread(thread_2); thread_1->start(); thread_2->start();
@
-
Tips and suggestions:
-
Do not put connection specifiers in your connects. Unless it is necessary (and there are few cases when it is like if you WANT different than default behaviour) you should trust qt to choose correctly.
-
If you are using Qt 5 switch to the new syntax. It looks clearer and is checked and decided during compile time.
-
Connect QThread::finished() to its deleteLater() and to its worker's deleteLater() and do NOT parent either:
@
connect(thread_1, &QThread::finished, thread_1, &QThread::deleteLater);
connect(thread_1, &QThread::finished, worker_1, &tcp_worker::deleteLater);
@- Move this bit to the beginning BEFORE your connections:
@
worker_1->moveToThread(thread_1);
worker_2->moveToThread(thread_2);
@It will make sure that Qt will make the connections correctly because I am not all too sure that they work correctly after you moved the object to another thread. They should but better be on a safe side.
-