• 2449阅读
  • 4回复

Qt线程同步问题 [复制链接]

上一主题 下一主题
离线songhuirong1
 

只看楼主 倒序阅读 楼主  发表于: 2019-07-26
直接上代码:
  1. #include <QCoreApplication>
  2. #include <QtConcurrent>
  3. #include <QWaitCondition>
  4. #include <QDebug>
  5. QMutex mutex;
  6. QWaitCondition wc;
  7. void testFunc()
  8. {
  9.     qDebug() << "exec testFunc...";
  10.     wc.wakeAll();
  11. }
  12. int main(int argc, char *argv[])
  13. {
  14.     QCoreApplication a(argc, argv);
  15.     QtConcurrent::run(testFunc);
  16.     QThread::sleep(3);
  17.     {
  18.         QMutexLocker locker(&mutex);
  19.         if (!wc.wait(&mutex))
  20.         {
  21.             return -1;
  22.         }
  23.         qDebug() << "wait for testFunc end...";
  24.     }
  25.     return a.exec();
  26. }

这段代码的意图是让主线程等待testFunc函数执行线程结束,然后testFunc函数执行线程唤醒主线程。但是由于主线程sleep了3s,那么testFunc函数执行线程瞬间就执行结束了,它调用了wc.wakeAll()函数,但是此时主线程还没有执行到wc.wait(&mutex)处,所以此时wakeAll无效,子线程执行结束。过了3
s后,主线程执行到wc.wait()处,由于testFunc函数执行线程已经结束,所以再也没有其它线程可以唤醒它,然后主程序就将永远wait。然后我修改了代码解决此问题,请各位看看我写的有没有问题,或者说有没有隐藏的bug。新的代码如下:
  1. #include <QCoreApplication>
  2. #include <QtConcurrent>
  3. #include <QWaitCondition>
  4. #include <QDebug>
  5. QMutex mutex;
  6. QWaitCondition wc;
  7. void testFunc()
  8. {
  9.     {
  10.         qDebug() << "testFunc wait start...";
  11.         QMutexLocker locker(&mutex);
  12.         wc.wait(&mutex);
  13.         qDebug() << "testFunc wait end...";
  14.     }
  15.     QMutexLocker locker(&mutex);
  16.     qDebug() << "exec testFunc...";
  17.     wc.wakeAll();
  18.     qDebug() << "testFunc wakeAll...";
  19. }
  20. int main(int argc, char *argv[])
  21. {
  22.     QCoreApplication a(argc, argv);
  23.     qDebug() << "start call testFunc...";
  24.     QtConcurrent::run(testFunc);
  25.     QThread::sleep(3);
  26.     {
  27.         qDebug() << "wait for testFunc start...";
  28.         QMutexLocker locker(&mutex);
  29.         wc.wakeAll();
  30.         qDebug() << "main wakeAll...";
  31.         if (!wc.wait(&mutex))
  32.         {
  33.             return -1;
  34.         }
  35.         qDebug() << "wait for testFunc end...";
  36.     }
  37.     return a.exec();
  38. }



离线fsu0413

只看该作者 1楼 发表于: 2019-07-26
难道你的代码就没有一个用mutex保护的量来标志testFunc是否执行完吗?


  1. #include <QCoreApplication>
  2. #include <QtConcurrent>
  3. #include <QWaitCondition>
  4. #include <QDebug>
  5. QMutex mutex;
  6. QWaitCondition wc;
  7. bool flag=false;
  8. void testFunc()
  9. {
  10.     qDebug() << "exec testFunc...";
  11.     QMutexLocker locker(&mutex);
  12.     flag = true;
  13.     wc.wakeAll();
  14. }
  15. int main(int argc, char *argv[])
  16. {
  17.     QCoreApplication a(argc, argv);
  18.     QtConcurrent::run(testFunc);
  19.     QThread::sleep(3);
  20.     {
  21.         QMutexLocker locker(&mutex);
  22.         if (!flag)
  23.             if (!wc.wait(&mutex))
  24.             {
  25.                 return -1;
  26.             }
  27.         qDebug() << "wait for testFunc end...";
  28.     }
  29.     return a.exec();
  30. }

离线songhuirong1

只看该作者 2楼 发表于: 2019-07-27
回 fsu0413 的帖子
fsu0413:难道你的代码就没有一个用mutex保护的量来标志testFunc是否执行完吗?
#include <QCoreApplication>
#include <QtConcurrent>
....... (2019-07-26 22:30) 

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

只看该作者 3楼 发表于: 2019-09-23
新的例子代码,更加简洁。
    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

只看该作者 4楼 发表于: 2019-09-23
新的例子代码,更加简洁。
  1. template <typename Type>
  2.     bool common_kit::RemoteControlHelper::readRequest(int varid, int vartype, Type &data, int offset /*= 0*/)
  3.     {
  4.         if (m_dataStream.isNull())
  5.         {
  6.             Q_ASSERT(false);
  7.             return false;
  8.         }
  9.         if (gdp::core::INVALID_ID == m_mtManualId)
  10.         {
  11.             Q_ASSERT(false);
  12.             return false;
  13.         }
  14.         mn::common_title common_title_;
  15.         mn::common_title_item common_title_item_;
  16.         common_title_item_.varid = varid;
  17.         common_title_item_.offset = offset;
  18.         common_title_item_.vartype = vartype;
  19.         common_title_item_.length = sizeof(data);
  20.         common_title_.items.push_back(common_title_item_);
  21.         bool bOk = false;
  22.         QMutex mutex;
  23.         QMutexLocker mutexLocker(&mutex);
  24.         QWaitCondition wc;
  25.         int ret = m_dataStream->mt_post_common_read_request_by_id(m_mtManualId, common_title_, [&](uint32_t mtManualId, const void *pdata){
  26.             QMutexLocker mutextLocker(&mutex);
  27.             [&](){
  28.                 if (mtManualId != m_mtManualId)
  29.                 {
  30.                     qDebug() << Q_FUNC_INFO << "\nmt manual id is not match!mtManualId:" << mtManualId << "\tm_mtManualId:" << m_mtManualId
  31.                         << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;
  32.                     return;
  33.                 }
  34.                 if (Q_NULLPTR == pdata)
  35.                 {
  36.                     qDebug() << Q_FUNC_INFO << "\npdata is null!mtManualId:" << mtManualId
  37.                         << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;
  38.                     return;
  39.                 }
  40.                 mn::asio_t *pasio_t = (mn::asio_t *)pdata;
  41.                 if (Q_NULLPTR == pasio_t)
  42.                 {
  43.                     qDebug() << Q_FUNC_INFO << "\npasio_t is null!mtManualId:" << mtManualId
  44.                         << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;
  45.                     return;
  46.                 }
  47.                 int err_ = pasio_t->err_;
  48.                 if (err_ < 0)
  49.                 {
  50.                     qDebug() << Q_FUNC_INFO << "\nread request failed!mtManualId:" << mtManualId
  51.                         << "\terr_:" << err_ << "\tvarid:" << varid << "\tvartype:" << vartype
  52.                         << "\toffset:" << offset;
  53.                     return;
  54.                 }
  55.                 mn::common_data *pcommon_data = (mn::common_data *)pdata;
  56.                 if (Q_NULLPTR == pcommon_data)
  57.                 {
  58.                     qDebug() << Q_FUNC_INFO << "\npcommon_data is null!mtManualId:" << mtManualId
  59.                         << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;
  60.                     return;
  61.                 }
  62.                 if (pcommon_data->items.empty())
  63.                 {
  64.                     qDebug() << Q_FUNC_INFO << "\npcommon_data's items is empty!mtManualId:" << mtManualId
  65.                         << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;
  66.                     return;
  67.                 }
  68.                 mn::common_data_item ack = pcommon_data->items[0];
  69.                 char *pack_data = (char *)(ack.data.data());
  70.                 if (Q_NULLPTR == pack_data)
  71.                 {
  72.                     qDebug() << Q_FUNC_INFO << "\npack_data is null!mtManualId:" << mtManualId
  73.                         << "\tvarid:" << varid << "\tvartype:" << vartype << "\toffset:" << offset;
  74.                     return;
  75.                 }
  76.                 data = *(Type *)pack_data;
  77.                 bOk = true;
  78.             }();
  79.             wc.wakeAll();
  80.         });
  81.         if (ret < 0)
  82.         {
  83.             return false;
  84.         }
  85.         if (!wc.wait(&mutex, READ_REQUEST_TIMEOUT))
  86.         {
  87.             qDebug() << Q_FUNC_INFO << "\nQWaitCondition wait failed!m_mtManualId:" << m_mtManualId;
  88.             return false;
  89.         }
  90.         return bOk;
  91.     }

快速回复
限100 字节
 
上一个 下一个