我正在研究QT框架中的数据记录器。我打算将日志字符串保存到文件并在单独的观察程序线程中打印到控制台。在那个单独的线程中,我需要为添加的新项目观察我的QStringList。如果有新项目,我将它们deque并记录。我想知道在Qt框架中使用的机制是什么。在STD lib中,我使用condition_variable
执行此任务,如下所示:
/*!
* \brief puts a \ref logline_t object at the end of the queue
* @param s object to be added to queue
*/
void CLogger::push_back(logline_t* s)
{
unique_lock<mutex> ul(m_mutex2);
s->queSize = m_data.size();
m_data.emplace_back(move(s));
m_cv.notify_all();
}
/*!
* \brief takes a \ref logline_t object from the beggining of the queue
* @return first \ref logline_t object
*/
CLogger::logline_t CLogger::pop_front()
{
unique_lock<mutex> ul(m_mutex2);
m_cv.wait(ul, [this]() { return !m_data.empty(); });
assert(m_data.front());
logline_t retVal = move(*m_data.front());
delete m_data.front();
m_data.front() = NULL;
m_data.pop_front();
return retVal;
}
m_cv
是条件变量对象。如何通过QT获取此功能?我打赌有更好的方式:)。我将非常感谢所有的帮助。
Ps:我知道指针函数参数没有断言,这是一个旧代码......:P
答案 0 :(得分:2)
在Qt中有几种方法可以进行通知。
信号和广告位
可以在线程之间发送信号和插槽,在建立连接时,将连接类型设置为Qt::QueuedConnection or Qt::BlockingQueuedConnection。
您可能希望围绕QStringList创建一个包装类,以便修改可以触发其他类侦听的信号。
QMutex和QWaitCondition
您可以使用Qt线程同步类QMutex和QWaitCondition来执行经典的手动同步,就像您之前所做的那样。使用QMutex时,QMutexLocker对于范围锁定和QMutex的发布非常有用。
答案 1 :(得分:1)
以下是执行此信号和插槽的示例。您可能想要自己的基准来测试这是否符合您的需求。另请注意,虽然信号和插槽可确保线程安全,但它们并不保证消息的显示顺序与发送顺序相同。话虽如此,我已经使用了这种机制多年,但它还没有发生在我身上。
首先,创建几个类:
#include "loggee.hpp"
void Loggee::someEventHappened(int id)
{
auto toLog = QString::number(id);
emit newLogLineNotify(toLog);
}
和.cpp文件:
#ifndef LOGGER_HPP
#define LOGGER_HPP
#include <QObject>
class Logger : public QObject
{
Q_OBJECT
public:
using QObject::QObject;
signals:
public slots:
void onLogEventHappened(QString const&);
};
#endif // LOGGER_HPP
#include <QDebug>
#include <QThread>
#include "logger.hpp"
void Logger::onLogEventHappened(QString const& str)
{
qDebug() << QThread::currentThreadId() << str;
}
和.cpp文件:
#include <QDebug>
#include <QThread>
#include <QCoreApplication>
#include <QTimer>
#include "logger.hpp"
#include "loggee.hpp"
int main(int argc, char** argv)
{
QCoreApplication a(argc, argv);
QThread t;
t.start();
Logger foo;
Loggee bar;
foo.moveToThread(&t);
QObject::connect(&bar, &Loggee::newLogLineNotify,
&foo, &Logger::onLogEventHappened,
Qt::AutoConnection);
qDebug() << "Current thread id: " << QThread::currentThreadId();
bar.someEventHappened(42);
QTimer::singleShot(3000, [&]{ bar.someEventHappened(43); });
return a.exec();
}
QThread
在这个演示中,我创建了一个Logger
和一个Logger
,将这个新Loggee
的插槽移动到这个新线程的事件循环中。然后,我使用Logger
将Qt::AutoConnection
的信号与Qt::QueuedConnection
的广告连接。这是默认设置,但我明确表示可以更改此设置(即Loggee
,即使两个线程都在同一个线程中,也会对插槽的执行进行排队。)
然后我让emit
发出¹信号。它被正确调度并导致日志记录槽在接收者的线程中执行。
¹#define emit /*null*/
为project
,因此如果您愿意,可以省略
答案 2 :(得分:1)
如果您只是在寻找您使用的类的Qt等价物:
std::mutex -> QMutex
std::condition_variable -> QWaitCondition
std::unique_lock -> QMutexLocker