【问题标题】:C++/Qt: How to create a busyloop which you can put on pause?C++/Qt:如何创建一个可以暂停的busyloop?
【发布时间】:2022-01-17 08:07:59
【问题描述】:

对于这个问题,有没有比使用在循环中检查的全局布尔标志创建类似自旋锁的结构更好的答案?

bool isRunning = true;

void busyLoop()
{
    for (;;) {
        if (!isRunning)
            continue;
        // ...
    }
}

int main()
{
    // ...
    QPushButton *startBusyLoopBtn = new QPushButton("start busy loop");
    QObject::connect(startBusyLoopBtn, QPushButton::clicked, [](){ busyLoop(); });
    
    QPushButton *startPauseBtn = new QPushButton("start/pause");
    QObject::connect(startPauseBtn, QPushButton::clicked, [](){ isRunning = !isRunning; });
    // ...
}

首先,我们在检查标志时浪费了 CPU 时间。其次,我们需要两个单独的按钮才能使该方案起作用。我们如何使用 Qt 的 slot-signal 机制来获得更简单的解决方案?

【问题讨论】:

  • 看看std::condition_variable。我不知道 Qt 是否有它自己的实现。您可以使用它创建启动/暂停/停止机制,而不是在循环中检查变量,这将使线程进入睡眠状态,直到它被通知继续。
  • 您需要以某种方式进行检查。我认为仅将繁忙循环作为插槽运行是不合适的,因为事件将由事件队列处理并阻止所有后续事件处理。您最好作为工作线程执行此操作,我同意它可以坐下来等待条件变量在激活之前发出信号(然后使用适当的同步测试标志以关闭)。或者您可以生成并终止线程以响应这些按钮——虽然有点危险。为了减少标志测试的“负载”,通过批处理繁忙的部分来减少测试的频率。
  • 如果您打算在“buysy 循环”中做一些工作,可以暂停和恢复,并且在主线程中执行此操作但仍然具有 GUI 响应,您应该添加 QCoreApplication::processEvents() 到你的繁忙循环并经常调用它。否则您的代码将无法工作,因为主线程将被“忙循环”阻塞。然而,这不是一个理想的解决方案。您应该了解更多关于 Qt 中的多线程的信息。但这是非常高级的话题。
  • @V.K.是的,我的实际代码中确实有它。
  • @kenticent 仔细阅读我的回答,那里有你需要的一切。如果您需要帮助,请不要犹豫。

标签: c++ qt


【解决方案1】:

你可以使用std::condition_variable:

    std::mutex mtx;
    std::condition_variable cv_start_stop;

    std::thread thr([&](){
        /**
         * this thread will notify and unpause the main loop 3 seconds later
         */
        std::this_thread::sleep_for(std::chrono::milliseconds(3000));
        cv_start_stop.notify_all();
    });

    bool paused = true;
    while (true)
    {
        if (paused)
        {
            std::unique_lock<std::mutex> lock(mtx);
            cv_start_stop.wait(lock); // this will lock the thread until notified.
            std::cout << "thread unpaused\n";
            paused = false;
        }
        std::cout << "loop goes on until paused\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }

这不会粗暴地检查标志是否继续,而是会让线程进入休眠状态,直到收到通知。

您只需让paused = true; 暂停,cv_start_stop.notify_one();cv_start_stop.notify_all(); 取消暂停。

【讨论】:

    猜你喜欢
    • 2011-04-14
    • 1970-01-01
    • 2012-10-12
    • 1970-01-01
    • 1970-01-01
    • 2012-07-23
    • 2021-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多