当在Qt C++中使用多线程进行串口通讯时,由于串口的阻塞读取特性,必要的线程同步和数据保护也是非常重要的。以下给出一个实现多个线程共享一个串口实例的示例程序,并使用QMutex作为线程同步机制来确保资源的安全访问:
- 创建一个名为SerialPortManager的单例类,该类封装了串口的打开、关闭、读写等操作并提供给其他线程调用:
class SerialPortManager : public QObject {
Q_OBJECT
public:
static SerialPortManager* instance() {
static SerialPortManager* manager = nullptr;
if (!manager) {
manager = new SerialPortManager();
}
return manager;
}
bool open(const QString& portName, int baudRate, int dataBits, QSerialPort::Parity parity, QSerialPort::StopBits stopBits) {
QMutexLocker locker(&mutex);
serialPort.setPortName(portName);
serialPort.setBaudRate(baudRate);
serialPort.setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
serialPort.setParity(parity);
serialPort.setStopBits(stopBits);
return serialPort.open(QIODevice::ReadWrite);
}
void close() {
QMutexLocker locker(&mutex);
serialPort.close();
}
QByteArray read(int maxSize) {
QMutexLocker locker(&mutex);
return serialPort.read(maxSize);
}
void write(const QByteArray& data) {
QMutexLocker locker(&mutex);
serialPort.write(data);
}
signals:
void readyRead();
private slots:
void onReadyRead() {
emit readyRead();
}
private:
SerialPortManager(QObject* parent = nullptr) : QObject(parent) {
connect(&serialPort, &QSerialPort::readyRead, this, &SerialPortManager::onReadyRead);
}
QMutex mutex;
QSerialPort serialPort;
};
在此类中,我们使用了一个名为mutex的QMutex对象来确保对串口资源的线程安全访问。值得注意的是,我们将SerialPortManager定义为单例类,以便能够在主线程和其他线程之间共享一个串口实例。
- 在不同的线程中使用SerialPortManager类进行串口通讯:
// 在主线程中打开串口
SerialPortManager::instance()->open("COM1", 115200, 8, QSerialPort::NoParity, QSerialPort::OneStop);
// 在工作线程中读取串口数据并发送信号
class WorkerThread : public QThread {
Q_OBJECT
signals:
void messageReceived(const QByteArray& message);
protected:
void run() {
while (!isInterruptionRequested()) {
QByteArray data = SerialPortManager::instance()->read(1024);
if (!data.isEmpty()) {
emit messageReceived(data);
}
}
}
};
// 在UI线程中连接信号槽处理串口数据
connect(workerThread, &WorkerThread::messageReceived, this, [this](const QByteArray& message) {
// 处理收到的串口数据
});
在上面的代码中,我们在主线程中使用SerialPortManager类打开了一个串口,并在工作线程中使用SerialPortManager类读取串口数据。此外,我们还定义了一个messageReceived信号,该信号将从工作线程发送到主线程并传递接收到的字节数组。
需要注意的是,在进行串口通讯时,要确保在每个线程中只有一个实例对象访问该串口,以确保不会在多个线程同时读写同一个串口实例而导致数据混乱或者串口被关闭等问题。