之前自己写了一个收数据的功能,但是没有数据的时候就要不停监听,那监听多久合适呢?1ms ?10 ms ? 100ms?但是你也不确定数据什么时候来,那么就可以使用经典的生产者消费者模型。这次的实验中我参考了人民邮电出版社<<Qt5.9 C++开发指南>>中的实现。
原书中的实现,将锁和同步量声明为全局变量,并不是很优雅。我们可以实现一个管理类, 将锁和同步量写在管理类里边,管理类管理生产者和消费者,生产者和消费者都可以看到管理类内的互斥量和同步量,代码结构如下:
管理类ThreadManager
头文件的声明如下:
#ifndef THREADMANAGER_H
#define THREADMANAGER_H#include <QMutex>
#include <QObject>
#include <QThread>
#include <QSharedPointer>
#include <QScopedPointer>
#include <QMutexLocker>
#include <QWaitCondition>
#include <ProducerThread.h>
#include <ConsumerThread.h>class ThreadManager: public QObject
{Q_OBJECT
public:ThreadManager();void initConnections();void start();private:QSharedPointer<QMutex> m_mutex;QSharedPointer<QWaitCondition> m_waitCondition;QScopedPointer<ProducerThread> m_producer;QScopedPointer<ConsumerThread> m_consumer;
};#endif // THREADMANAGER_H
因为互斥量mutex是不支持赋值的,所以可以用共享指针给管理起来,然后在生产者和消费者线程中都声明同样的共享指针,指向同一个互斥量和同步量。.cpp实现如下:
#include "ThreadManager.h"ThreadManager::ThreadManager(): m_consumer(new ConsumerThread(this)), m_producer(new ProducerThread(this)), m_mutex(new QMutex), m_waitCondition(new QWaitCondition)
{m_producer->setSharedMutex(m_mutex);m_producer->setSharedCondition(m_waitCondition);m_consumer->setSharedMutex(m_mutex);m_consumer->setSharedCondition(m_waitCondition);initConnections();
}void ThreadManager::initConnections()
{connect(m_producer.data(), &ProducerThread::sendData,m_consumer.data(), &ConsumerThread::comsumeData);
}void ThreadManager::start()
{m_consumer->start();m_producer->updateStopState(true);m_producer->start();
}
函数的其他说明:构造函数, m_producer与m_consumer, 都设置好互斥量和同步量的共享指针;initConnections(): 连接生产者与消费者;start():模拟启动。
生产者ProducerThread
声明如下:
#ifndef PRODUCERTHREAD_H
#define PRODUCERTHREAD_H#include <QSharedPointer>
#include <QWaitCondition>
#include <QThread>
#include <QDebug>
#include <QMutexLocker>class ProducerThread: public QThread
{Q_OBJECT
public:explicit ProducerThread(QObject *parent);void updateStopState(bool state) {m_state = state;}void setSharedMutex(QSharedPointer<QMutex> point);void setSharedCondition(QSharedPointer<QWaitCondition> point);private:bool m_state;int m_startVal;QSharedPointer<QMutex> m_mutex;QSharedPointer<QWaitCondition> m_waitCondition;protected:void run() override;signals:void sendData(int val);
};#endif // PRODUCERTHREAD_H
函数说明:updateStopState():决定是否继续发数据;setSharedMutex()和setSharedContition(),给成员变量m_mutex以及m_waitCondition赋值,指向管理者的互斥量与同步量;定义好signal,sendData()用来发送数据。.cpp实现如下:
#include "ProducerThread.h"
#include "ThreadManager.h"ProducerThread::ProducerThread(QObject *parent): m_state(false), m_startVal(0)
{
}void ProducerThread::setSharedMutex(QSharedPointer<QMutex> point)
{m_mutex = point;
}void ProducerThread::setSharedCondition(QSharedPointer<QWaitCondition> point)
{m_waitCondition = point;
}void ProducerThread::run()
{while(m_state) {QMutexLocker lock(m_mutex.data());qDebug() << "Send Data: " << QString::number(m_startVal);emit sendData(m_startVal++);lock.unlock();m_waitCondition->wakeOne();QThread::sleep(2);}
}
在run()函数中,不停加锁再发数据,发数据后用wakeOne()唤醒正在阻塞的消费者,然后中间间隔2s。
消费者ConsumerThread
#ifndef CONSUMERTHREAD_H
#define CONSUMERTHREAD_H#include <QDebug>
#include <QThread>
#include <QMutexLocker>
#include <QSharedPointer>
#include <QWaitCondition>class ConsumerThread: public QThread
{Q_OBJECT
public:explicit ConsumerThread(QObject *parent);void updateState(bool state) {m_state = state;}void setSharedMutex(QSharedPointer<QMutex> point);void setSharedCondition(QSharedPointer<QWaitCondition> point);private:bool m_state;int m_data;QSharedPointer<QMutex> m_mutex;QSharedPointer<QWaitCondition> m_waitCondition;protected:void run() override;public slots:void comsumeData(int val);
};#endif // CONSUMERTHREAD_H
逻辑基本和生产者一样,定义好槽函数,用来处理数据即可。
#include "ConsumerThread.h"
#include "ThreadManager.h"ConsumerThread::ConsumerThread(QObject *parent): m_state(true)
{
}void ConsumerThread::setSharedMutex(QSharedPointer<QMutex> point)
{m_mutex = point;
}void ConsumerThread::setSharedCondition(QSharedPointer<QWaitCondition> point)
{m_waitCondition = point;
}void ConsumerThread::comsumeData(int val)
{m_data = val;
}void ConsumerThread::run()
{while(m_state) {QMutexLocker lock(m_mutex.data());m_waitCondition->wait(m_mutex.data());qDebug() << "Consume Data: " << m_data;lock.unlock();}
}
run()中的部分比较重要,现加锁,再通过wait解锁,等待唤醒,得到数据就打印。
主函数
#include "mainwindow.h"
#include <QDebug>
#include <QApplication>
#include "ThreadManager.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;// w.show();ThreadManager manager;manager.start();qDebug() << "Finished!";return a.exec();
}
通过manager.start()开始模拟,执行结果如下:
OK,模拟完毕!!