查看完整版本: [-- Qt线程同步问题 --]

QTCN开发网 -> Qt基础编程 -> Qt线程同步问题 [打印本页] 登录 -> 注册 -> 回复主题 -> 发表主题

songhuirong1 2019-07-26 09:41

Qt线程同步问题

直接上代码:
  1. #include <QCoreApplication>
    #include <QtConcurrent>
    #include <QWaitCondition>
    #include <QDebug>

    QMutex mutex;
    QWaitCondition wc;

    void testFunc()
    {
        qDebug() << "exec testFunc...";
        wc.wakeAll();
    }

    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        QtConcurrent::run(testFunc);
        QThread::sleep(3);

        {
            QMutexLocker locker(&mutex);

            if (!wc.wait(&mutex))
            {
                return -1;
            }

            qDebug() << "wait for testFunc end...";
        }

        return a.exec();
    }

这段代码的意图是让主线程等待testFunc函数执行线程结束,然后testFunc函数执行线程唤醒主线程。但是由于主线程sleep了3s,那么testFunc函数执行线程瞬间就执行结束了,它调用了wc.wakeAll()函数,但是此时主线程还没有执行到wc.wait(&mutex)处,所以此时wakeAll无效,子线程执行结束。过了3
s后,主线程执行到wc.wait()处,由于testFunc函数执行线程已经结束,所以再也没有其它线程可以唤醒它,然后主程序就将永远wait。然后我修改了代码解决此问题,请各位看看我写的有没有问题,或者说有没有隐藏的bug。新的代码如下:
  1. #include <QCoreApplication>
    #include <QtConcurrent>
    #include <QWaitCondition>
    #include <QDebug>

    QMutex mutex;
    QWaitCondition wc;

    void testFunc()
    {
        {
            qDebug() << "testFunc wait start...";
            QMutexLocker locker(&mutex);
            wc.wait(&mutex);
            qDebug() << "testFunc wait end...";
        }

        QMutexLocker locker(&mutex);
        qDebug() << "exec testFunc...";
        wc.wakeAll();
        qDebug() << "testFunc wakeAll...";
    }

    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        qDebug() << "start call testFunc...";
        QtConcurrent::run(testFunc);
        QThread::sleep(3);

        {
            qDebug() << "wait for testFunc start...";
            QMutexLocker locker(&mutex);
            wc.wakeAll();
            qDebug() << "main wakeAll...";

            if (!wc.wait(&mutex))
            {
                return -1;
            }

            qDebug() << "wait for testFunc end...";
        }

        return a.exec();
    }




fsu0413 2019-07-26 22:30
难道你的代码就没有一个用mutex保护的量来标志testFunc是否执行完吗?


  1. #include <QCoreApplication>
    #include <QtConcurrent>
    #include <QWaitCondition>
    #include <QDebug>

    QMutex mutex;
    QWaitCondition wc;
    bool flag=false;

    void testFunc()
    {
        qDebug() << "exec testFunc...";
        QMutexLocker locker(&mutex);
        flag = true;
        wc.wakeAll();
    }

    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        QtConcurrent::run(testFunc);
        QThread::sleep(3);

        {
            QMutexLocker locker(&mutex);

            if (!flag)
                if (!wc.wait(&mutex))
                {
                    return -1;
                }

            qDebug() << "wait for testFunc end...";
        }

        return a.exec();
    }


songhuirong1 2019-07-27 16:21
fsu0413:难道你的代码就没有一个用mutex保护的量来标志testFunc是否执行完吗?
#include <QCoreApplication>
#include <QtConcurrent>
....... (2019-07-26 22:30) 

非常感谢你的回复,你的代码应该也是可以解决问题的,只是我们实现的方式不一样而已,我的代码应该是没有问题的。我只是想向各位学习一下,看有没有更好的实现方式。你的这种方法给我提供了一种新的思路,我学习了。谢谢。如果我的代码有纰漏,还望指点一二。

songhuirong1 2019-09-23 07:12
新的例子代码,更加简洁。
    template <typename Type>
    bool common_kit::RemoteControlHelper::readRequest(int varid, int vartype, Type &data, int offset /*= 0*/)
    {
        if (m_dataStream.isNull())
        {
            Q_ASSERT(false);

            return false;
        }

        if (gdp::core::INVALID_ID == m_mtManualId)
        {
            Q_ASSERT(false);

            return false;
        }

        mn::common_title common_title_;
        mn::common_title_item common_title_item_;
        common_title_item_.varid = varid;
        common_title_item_.offset = offset;
        common_title_item_.vartype = vartype;
        common_title_item_.length = sizeof(data);
        common_title_.items.push_back(common_title_item_);
        bool bOk = false;
        QMutex mutex;
        QMutexLocker mutexLocker(&mutex);
        QWaitCondition wc;
        int ret = m_dataStream->mt_post_common_read_request_by_id(m_mtManualId, common_title_, [&](uint32_t mtManualId, const void *pdata){
            QMutexLocker mutextLocker(&mutex);
            [&](){
                if (mtManualId != m_mtManualId)
                {
                    qDebug() << Q_FUNC_INFO << "\nmt manual id is not match!mtManualId:" << mtManualId << "\tm_mtManualId:" << m_mtManualId
                        << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;

                    return;
                }

                if (Q_NULLPTR == pdata)
                {
                    qDebug() << Q_FUNC_INFO << "\npdata is null!mtManualId:" << mtManualId
                        << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;

                    return;
                }

                mn::asio_t *pasio_t = (mn::asio_t *)pdata;

                if (Q_NULLPTR == pasio_t)
                {
                    qDebug() << Q_FUNC_INFO << "\npasio_t is null!mtManualId:" << mtManualId
                        << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;

                    return;
                }

                int err_ = pasio_t->err_;

                if (err_ < 0)
                {
                    qDebug() << Q_FUNC_INFO << "\nread request failed!mtManualId:" << mtManualId
                        << "\terr_:" << err_ << "\tvarid:" << varid << "\tvartype:" << vartype
                        << "\toffset:" << offset;

                    return;
                }

                mn::common_data *pcommon_data = (mn::common_data *)pdata;

                if (Q_NULLPTR == pcommon_data)
                {
                    qDebug() << Q_FUNC_INFO << "\npcommon_data is null!mtManualId:" << mtManualId
                        << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;

                    return;
                }

                if (pcommon_data->items.empty())
                {
                    qDebug() << Q_FUNC_INFO << "\npcommon_data's items is empty!mtManualId:" << mtManualId
                        << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;

                    return;
                }

                mn::common_data_item ack = pcommon_data->items[0];
                char *pack_data = (char *)(ack.data.data());

                if (Q_NULLPTR == pack_data)
                {
                    qDebug() << Q_FUNC_INFO << "\npack_data is null!mtManualId:" << mtManualId
                        << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;

                    return;
                }

                data = *(Type *)pack_data;
                bOk = true;
            }();

            wc.wakeAll();
        });

        if (ret < 0)
        {
            return false;
        }

        if (!wc.wait(&mutex, READ_REQUEST_TIMEOUT))
        {
            qDebug() << Q_FUNC_INFO << "\nQWaitCondition wait failed!m_mtManualId:" << m_mtManualId;

            return false;
        }

        return bOk;
    }

songhuirong1 2019-09-23 07:14
新的例子代码,更加简洁。
  1. template <typename Type>
        bool common_kit::RemoteControlHelper::readRequest(int varid, int vartype, Type &data, int offset /*= 0*/)
        {
            if (m_dataStream.isNull())
            {
                Q_ASSERT(false);

                return false;
            }

            if (gdp::core::INVALID_ID == m_mtManualId)
            {
                Q_ASSERT(false);

                return false;
            }

            mn::common_title common_title_;
            mn::common_title_item common_title_item_;
            common_title_item_.varid = varid;
            common_title_item_.offset = offset;
            common_title_item_.vartype = vartype;
            common_title_item_.length = sizeof(data);
            common_title_.items.push_back(common_title_item_);
            bool bOk = false;
            QMutex mutex;
            QMutexLocker mutexLocker(&mutex);
            QWaitCondition wc;
            int ret = m_dataStream->mt_post_common_read_request_by_id(m_mtManualId, common_title_, [&](uint32_t mtManualId, const void *pdata){
                QMutexLocker mutextLocker(&mutex);
                [&](){
                    if (mtManualId != m_mtManualId)
                    {
                        qDebug() << Q_FUNC_INFO << "\nmt manual id is not match!mtManualId:" << mtManualId << "\tm_mtManualId:" << m_mtManualId
                            << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;

                        return;
                    }

                    if (Q_NULLPTR == pdata)
                    {
                        qDebug() << Q_FUNC_INFO << "\npdata is null!mtManualId:" << mtManualId
                            << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;

                        return;
                    }

                    mn::asio_t *pasio_t = (mn::asio_t *)pdata;

                    if (Q_NULLPTR == pasio_t)
                    {
                        qDebug() << Q_FUNC_INFO << "\npasio_t is null!mtManualId:" << mtManualId
                            << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;

                        return;
                    }

                    int err_ = pasio_t->err_;

                    if (err_ < 0)
                    {
                        qDebug() << Q_FUNC_INFO << "\nread request failed!mtManualId:" << mtManualId
                            << "\terr_:" << err_ << "\tvarid:" << varid << "\tvartype:" << vartype
                            << "\toffset:" << offset;

                        return;
                    }

                    mn::common_data *pcommon_data = (mn::common_data *)pdata;

                    if (Q_NULLPTR == pcommon_data)
                    {
                        qDebug() << Q_FUNC_INFO << "\npcommon_data is null!mtManualId:" << mtManualId
                            << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;

                        return;
                    }

                    if (pcommon_data->items.empty())
                    {
                        qDebug() << Q_FUNC_INFO << "\npcommon_data's items is empty!mtManualId:" << mtManualId
                            << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;

                        return;
                    }

                    mn::common_data_item ack = pcommon_data->items[0];
                    char *pack_data = (char *)(ack.data.data());

                    if (Q_NULLPTR == pack_data)
                    {
                        qDebug() << Q_FUNC_INFO << "\npack_data is null!mtManualId:" << mtManualId
                            << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;

                        return;
                    }

                    data = *(Type *)pack_data;
                    bOk = true;
                }();

                wc.wakeAll();
            });

            if (ret < 0)
            {
                return false;
            }

            if (!wc.wait(&mutex, READ_REQUEST_TIMEOUT))
            {
                qDebug() << Q_FUNC_INFO << "\nQWaitCondition wait failed!m_mtManualId:" << m_mtManualId;

                return false;
            }

            return bOk;
        }



查看完整版本: [-- Qt线程同步问题 --] [-- top --]



Powered by phpwind v8.7 Code ©2003-2011 phpwind
Gzip disabled