2 thread send data To serial port
-
Good morning all
I am a new user of Qt creator and new to C ++
I wanted to make an application that sends a UART frame on the serial port every 100ms and another frame every 200ms I used an example code for the multithreaded I created 3 tasks to run at the same time and send different UART frames on the serial port but I manage to send just once at the start of the task i.e. if I run the task 1 at the start of the application it sends the UART frames
if I run task 2 when starting the application it sends the UART frames
each time the data I send the first time does not change even if I run the other task the goal is to send different data to each selected task.I share with you the code that I use and if you have any modifications to help me please tell me how to do it because I am a beginner
worker1.h
#ifndef WORKER1_H #define WORKER1_H #include <QObject> #include <QMutex> class Worker1 : public QObject { Q_OBJECT public: explicit Worker1(QObject *parent = nullptr); /** * @brief Requests the process to start * * It is thread safe as it uses #mutex to protect access to #_working variable. */ void requestWork1(); /** * @brief Requests the process to abort * * It is thread safe as it uses #mutex to protect access to #_abort variable. */ void abort1(); private: /** * @brief Process is aborted when @em true */ bool _abort1; /** * @brief @em true when Worker is doing work */ bool _working1; /** * @brief Protects access to #_abort */ QMutex mutex1; signals: /** * @brief This signal is emitted when the Worker request to Work * @sa requestWork() */ void workRequested1(); /** * @brief This signal is emitted when counted value is changed (every sec) */ void valueChanged1(const QString &value1); void moyenne(); /** * @brief This signal is emitted when process is finished (either by counting 60 sec or being aborted) */ void finished1(); public slots: /** * @brief Does something * * Counts 60 sec in this example. * Counting is interrupted if #_aborted is set to true. */ void doWork1(); }; #endif // WORKER1_H
worker1.cpp
#include "worker1.h" #include <QTimer> #include <QEventLoop> #include <QThread> #include <QDebug> #include "global.h" #include <windows.h> #include <qdebug.h> #include <QApplication> #include <QTextEdit> #include <QFile> #include <QString> #include <QTextStream> #include <QInputDialog> #include <QIODevice> #include <QMessageBox> #include <QtGui> #include <QTextEdit> #include <QLineEdit> #include <QThread> #include <QtWidgets> #include <QDir> #include <QCoreApplication> #include <cmath> #include <cstdio> #include <stdio.h> #include <QWidget> #include <QPaintEvent> #include <QPixmap> #include <QPainter> #include <QTimer> #include <QtCore> #include <QLabel> #include <QComboBox> #include <QVBoxLayout> #include <QSerialPort> QByteArray Worker1_array; Worker1::Worker1(QObject *parent) : QObject(parent) { _working1 =false; _abort1 = false; } void Worker1::requestWork1() { mutex1.lock(); _working1 = true; _abort1 = false; qDebug()<<"Request worker start in Thread "<<thread()->currentThreadId(); mutex1.unlock(); emit workRequested1(); } void Worker1::abort1() { mutex1.lock(); if (_working1) { _abort1 = true; qDebug()<<"Request worker aborting in Thread "<<thread()->currentThreadId(); } mutex1.unlock(); } void Worker1::doWork1() { qDebug()<<"Starting worker process in Thread "<<thread()->currentThreadId(); for (int i1 = 0; i1 < 60; i1 ++) { // Checks if the process should be aborted mutex1.lock(); bool abort1 = _abort1; mutex1.unlock(); if (abort1) { qDebug()<<"Aborting worker process in Thread "<<thread()->currentThreadId(); break; } // This will stupidly wait 1 sec doing nothing... QEventLoop loop1; QTimer::singleShot(100, &loop1, SLOT(quit())); loop1.exec(); // Once we're done waiting, value is updated emit valueChanged1(QString::number(i1)); Worker1_array[0] = 0x01; Worker1_array[1] = 0x01; Worker1_array[2] = 0x01; Worker1_array[3] = 0x01; Worker1_array[4] = 0x01; Worker1_array[5] = 0x01; Worker1_array[6] = 0x01; Worker1_array[7] = 0x01; Worker1_array[8] = 0x01; Worker1_array[9] = 0x01; Worker1_array[10] = 0x01; Worker1_array[11] = 0x01; Worker1_array[12] = 0x01; Worker1_array[13] = 0x01; Worker1_array[14] = 0x01; Worker1_array[15] = 0x01; serial_Main.write(Worker1_array,16); } // Set _working to false, meaning the process can't be aborted anymore. mutex1.lock(); _working1 = false; mutex1.unlock(); // qDebug()<<"Worker process finished in Thread "<<thread()->currentThreadId(); //Once 60 sec passed, the finished signal is sent emit finished1(); }
worker2.h
#ifndef WORKER2_H #define WORKER2_H #include <QObject> #include <QMutex> class Worker2 : public QObject { Q_OBJECT public: explicit Worker2(QObject *parent = nullptr); /** * @brief Requests the process to start * * It is thread safe as it uses #mutex to protect access to #_working variable. */ void requestWork2(); /** * @brief Requests the process to abort * * It is thread safe as it uses #mutex to protect access to #_abort variable. */ void abort2(); private: /** * @brief Process is aborted when @em true */ bool _abort2; /** * @brief @em true when Worker is doing work */ bool _working2; /** * @brief Protects access to #_abort */ QMutex mutex2; signals: /** * @brief This signal is emitted when the Worker request to Work * @sa requestWork() */ void workRequested2(); /** * @brief This signal is emitted when counted value is changed (every sec) */ void valueChanged2(const QString &value2); /** * @brief This signal is emitted when process is finished (either by counting 60 sec or being aborted) */ void finished2(); public slots: /** * @brief Does something * * Counts 60 sec in this example. * Counting is interrupted if #_aborted is set to true. */ void doWork2(); }; #endif // WORKER2_H
worker2.cpp
#include "worker2.h" #include <QTimer> #include <QEventLoop> #include <QThread> #include <QDebug> #include <windows.h> #include <qdebug.h> #include <QApplication> #include <QTextEdit> #include <QFile> #include <QString> #include <QTextStream> #include <QInputDialog> #include <QIODevice> #include <QMessageBox> #include <QtGui> #include <QTextEdit> #include <QLineEdit> #include <QThread> #include <QtWidgets> #include <QDir> #include <QCoreApplication> #include <cmath> #include <cstdio> #include <stdio.h> #include <QWidget> #include <QPaintEvent> #include <QPixmap> #include <QPainter> #include <QTimer> #include <QtCore> #include <QLabel> #include <QComboBox> #include <QVBoxLayout> #include <QSerialPort> #include "global.h" QByteArray Worker2_array; Worker2::Worker2(QObject *parent) : QObject(parent) { _working2 =false; _abort2 = false; } void Worker2::requestWork2() { mutex2.lock(); _working2 = true; _abort2 = false; qDebug()<<"Request worker start in Thread "<<thread()->currentThreadId(); mutex2.unlock(); emit workRequested2(); } void Worker2::abort2() { mutex2.lock(); if (_working2) { _abort2 = true; qDebug()<<"Request worker aborting in Thread "<<thread()->currentThreadId(); } mutex2.unlock(); } void Worker2::doWork2() { qDebug()<<"Starting worker process in Thread "<<thread()->currentThreadId(); for (int i2 = 0; i2 < 60; i2 ++) { // Checks if the process should be aborted mutex2.lock(); bool abort2 = _abort2; mutex2.unlock(); if (abort2) { qDebug()<<"Aborting worker process in Thread "<<thread()->currentThreadId(); break; } // This will stupidly wait 1 sec doing nothing... QEventLoop loop1; QTimer::singleShot(1000, &loop1, SLOT(quit())); loop1.exec(); // Once we're done waiting, value is updated emit valueChanged2(QString::number(i2)); Worker2_array[0] = 0x02; Worker2_array[1] = 0x02; Worker2_array[2] = 0x02; Worker2_array[3] = 0x02; Worker2_array[4] = 0x02; Worker2_array[5] = 0x02; Worker2_array[6] = 0x02; Worker2_array[7] = 0x02; Worker2_array[8] = 0x02; Worker2_array[9] = 0x02; Worker2_array[10] = 0x02; Worker2_array[11] = 0x02; Worker2_array[12] = 0x02; Worker2_array[13] = 0x02; Worker2_array[14] = 0x02; Worker2_array[15] = 0x02; serial_Main.write(Worker2_array,16); } // Set _working to false, meaning the process can't be aborted anymore. mutex2.lock(); _working2 = false; mutex2.unlock(); // qDebug()<<"Worker process finished in Thread "<<thread()->currentThreadId(); //Once 60 sec passed, the finished signal is sent emit finished2(); }
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QThread> #include "global.h" #include "worker1.h" #include "worker2.h" #include "worker3.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; QThread *thread1; QThread *thread2; QThread *thread3; /** * @brief Object which contains methods that should be runned in another thread */ Worker1 *worker1; Worker2 *worker2; Worker3 *worker3; /** * @brief Object which contains methods that should be runned in another thread */ private slots: void on_pushButton_clicked(); void on_pushButton_2_clicked(); void on_pushButton_3_clicked(); void on_pushButton_4_clicked(); void on_pushButton_5_clicked(); void on_pushButton_6_clicked(); }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include "global.h" #include <windows.h> #include <qdebug.h> #include <QApplication> #include <QTextEdit> #include <QFile> #include <QString> #include <QTextStream> #include <QInputDialog> #include <QIODevice> #include <QMessageBox> #include <QtGui> #include <QTextEdit> #include <QLineEdit> #include <QThread> #include <QtWidgets> #include <QDir> #include <QCoreApplication> #include <cmath> #include <cstdio> #include <stdio.h> #include <QWidget> #include <QPaintEvent> #include <QPixmap> #include <QPainter> #include <QTimer> #include <QtCore> #include <QLabel> #include <QComboBox> #include <QVBoxLayout> #include <QSerialPort> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); // The thread and the worker are created in the constructor so it is always safe to delete them. serial_Main.setPortName("COM8"); serial_Main.setBaudRate(115200); serial_Main.setDataBits(QSerialPort::Data8); serial_Main.setParity(QSerialPort::NoParity); serial_Main.setStopBits(QSerialPort::OneStop); serial_Main.setFlowControl(QSerialPort::NoFlowControl); serial_Main.open(QIODevice::ReadWrite); thread1 = new QThread(); worker1 = new Worker1(); thread2 = new QThread(); worker2 = new Worker2(); thread3 = new QThread(); worker3 = new Worker3(); worker1->moveToThread(thread1); connect(worker1, SIGNAL(valueChanged1(QString)), ui->label, SLOT(setText(QString))); connect(worker1, SIGNAL(workRequested1()), thread1, SLOT(start())); connect(thread1, SIGNAL(started()), worker1, SLOT(doWork1())); connect(worker1, SIGNAL(finished1()), thread1, SLOT(quit()), Qt::DirectConnection); worker2->moveToThread(thread2); connect(worker2, SIGNAL(valueChanged2(QString)), ui->label_2, SLOT(setText(QString))); connect(worker2, SIGNAL(workRequested2()), thread2, SLOT(start())); connect(thread2, SIGNAL(started()), worker2, SLOT(doWork2())); connect(worker2, SIGNAL(finished2()), thread2, SLOT(quit()), Qt::DirectConnection); worker3->moveToThread(thread3); connect(worker3, SIGNAL(valueChanged3(QString)), ui->label_3, SLOT(setText(QString))); connect(worker3, SIGNAL(workRequested3()), thread3, SLOT(start())); connect(thread3, SIGNAL(started()), worker3, SLOT(doWork3())); connect(worker3, SIGNAL(finished3()), thread3, SLOT(quit()), Qt::DirectConnection); } MainWindow::~MainWindow() { worker1->abort1(); thread1->wait(); qDebug()<<"Deleting thread and worker in Thread "<<this->QObject::thread()->currentThreadId(); delete thread1; delete worker1; worker2->abort2(); thread2->wait(); qDebug()<<"Deleting thread and worker in Thread "<<this->QObject::thread()->currentThreadId(); delete thread2; delete worker2; worker3->abort3(); thread3->wait(); qDebug()<<"Deleting thread and worker in Thread "<<this->QObject::thread()->currentThreadId(); delete thread3; delete worker3; delete ui; } void MainWindow::on_pushButton_clicked() { worker1->abort1(); thread1->wait(); // If the thread is not running, this will immediately return. worker1->requestWork1(); } void MainWindow::on_pushButton_2_clicked() { worker2->abort2(); thread2->wait(); // If the thread is not running, this will immediately return. worker2->requestWork2(); } void MainWindow::on_pushButton_3_clicked() { worker3->abort3(); thread3->wait(); // If the thread is not running, this will immediately return. worker3->requestWork3(); } void MainWindow::on_pushButton_4_clicked() { worker1->abort1(); thread1->wait(); qDebug()<<"Deleting thread and worker in Thread "<<this->QObject::thread()->currentThreadId(); delete thread1; delete worker1; } void MainWindow::on_pushButton_5_clicked() { worker2->abort2(); thread2->wait(); qDebug()<<"Deleting thread and worker in Thread "<<this->QObject::thread()->currentThreadId(); delete thread2; delete worker2; } void MainWindow::on_pushButton_6_clicked() { worker3->abort3(); thread3->wait(); qDebug()<<"Deleting thread and worker in Thread "<<this->QObject::thread()->currentThreadId(); delete thread3; delete worker3; }
Thank you for Help
-
Hi,
Beside @JKSH good point, you seem to be using a global object QSerialPort object that you are accessing from your various threads without any protections. This is wrong on several levels.
I also noted that you have tons of includes related to GUI elements in your workers code which might indicate that you are about to try and change GUI elements from secondary threads. This is also a no go.
If you really need these threads, then you should design a proper controller class for the serial port communication that will be shared between the workers and serialize/protect the access to the serial port.
-
Hi JKSH
Thank you for you support
/* I try to use qtimer but he dont' work correctly and i dont now whay
@bassem84 said in 2 thread send data To serial port:
I try to use qtimer but he dont' work correctly and i dont now whay
We neither as you did not provide any code and no error messages...
-
Hi JKSH
Thank you for you support
/* I try to use qtimer but he dont' work correctly and i dont now whay
@bassem84 said in 2 thread send data To serial port:
I try to use qtimer but he dont' work correctly and i dont now whay
Start by writing very simple code. First, try to use a QTimer to print a message to your console every 500ms. If you can't get it to work, post your code here like @jsulm said.
Notes:
- The code that you originally posted is quite complex. It is easier to help you when you post simple code.
- Threads are difficult to use correctly in C++. I recommend that beginners stay away from them.