Watch a QStringList for new items

2019-09-07 00:58发布

I am working on a data logger in QT framework. I Intend to save log strings to files and print to the console in a separate watcher thread. In that separate thread I need to watch my QStringList for new items added. If there are new items I deque them and log. I was wondering what is the mechanism used for this in Qt framework. In STD lib i used condition_variable for this task like this:

/*!
 * \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 is the conditional variable object. How can this functionality be acquired with QT? I bet there is a lot better way :). I would appreciate all help. Ps: I know pointer functions parameters are not asserted, this is an old code... :P

3条回答
祖国的老花朵
2楼-- · 2019-09-07 01:21

There are a couple of ways of doing the notification in Qt.

Signals and Slots

Signals and slots can be sent between threads, when making the connection, you set the connection type to Qt::QueuedConnection or Qt::BlockingQueuedConnection.

You may want to create a wrapper class around the QStringList so that modifications can trigger the signals that other classes listen for.

QMutex and QWaitCondition

You can use the Qt thread synchronisation classes QMutex and QWaitCondition to do the classic manual synchronisation like you have done previously. When using QMutex, the QMutexLocker is useful for scope lock and release of a QMutex.

查看更多
戒情不戒烟
3楼-- · 2019-09-07 01:29

Here's an example of doing this signals and slots. You may want to do your own benchmarks to test whether this fits your needs. Please also note that while signals and slots guarantee thread-safety, they don't guarantee that the messages will appear in the same order they were sent. That being said, I've used this mechanism for years and it has yet to happen for me.

First, create a couple of classes:

Loggee

// loggee.hpp
#ifndef LOGGEE_HPP
#define LOGGEE_HPP

#include <QObject>

class Loggee : public QObject
{
    Q_OBJECT
public:
    using QObject::QObject;


    void someEventHappened(int id);

signals:

    void newLogLineNotify(QString const&);
};

#endif // LOGGEE_HPP

and the .cpp file:

#include "loggee.hpp"

void Loggee::someEventHappened(int id)
{
    auto toLog = QString::number(id);
    emit newLogLineNotify(toLog);
}

Logger

#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

and the .cpp file:

#include <QDebug>
#include <QThread>

#include "logger.hpp"

void Logger::onLogEventHappened(QString const& str)
{
    qDebug() << QThread::currentThreadId() << str;
}

the rest

#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();
}

In this demo, I create a QThread and a Logger, move handling of this new Logger's slots to this new thread's event loop. Then I connect Loggee's signal with Logger's slot using Qt::AutoConnection. This is the default but I stated it explicitly to show that you can change this (i.e. to Qt::QueuedConnection which would queue the execution of the slot even if both threads lived in the same thread).

Then I cause the Loggee to emit¹ a singal. It gets properly scheduled and causes the logging slot to be executed in the receiver's thread.

¹ emit is #define emit /*null*/, so you can omit it if you want

查看更多
贼婆χ
4楼-- · 2019-09-07 01:30

If you are just looking for the Qt equivalents to the classes you have been using:

std::mutex -> QMutex
std::condition_variable -> QWaitCondition
std::unique_lock -> QMutexLocker
查看更多
登录 后发表回答