C++ std::async 在主线程上运行

标签 c++ multithreading asynchronous c++11 std

有没有办法在主线程上运行函数?

因此,如果我通过异步调用一个函数来下载文件,然后解析数据。然后它会调用一个回调函数,该函数将在我的主 UI 线程上运行并更新 UI?

我知道默认 C++ 实现中的线程是相等的,因此我必须创建一个指向主线程的共享指针。我该如何做到这一点,并将异步函数不仅传递到主线程的共享指针,而且传递到我想要在其上运行的函数的指针,然后在该主线程上运行它?

最佳答案

我一直在阅读 C++ Concurrency in Action 和第四章(又名“我刚刚完成的章节”)描述了一个解决方案。

简短版本

有共享std::deque<std::packaged_task<void()>> (或类似的消息/任务队列)。您的std::async -启动的函数可以将任务推送到队列,并且您的 GUI 线程可以在循环期间处理它们。

实际上没有很长的版本,但这里有一个示例

共享数据

std::deque<std::packaged_task<void()>> tasks;
std::mutex tasks_mutex;
std::atomic<bool> gui_running;

std::async功能

void one_off()
{
    std::packaged_task<void()> task(FUNCTION TO RUN ON GUI THREAD); //!!
    std::future<void> result = task.get_future();

    {
        std::lock_guard<std::mutex> lock(tasks_mutex);
        tasks.push_back(std::move(task));
    }

    // wait on result
    result.get();
}

GUI 线程

void gui_thread()
{
    while (gui_running) {
        // process messages
        {
            std::unique_lock<std::mutex> lock(tasks_mutex);
            while (!tasks.empty()) {
                auto task(std::move(tasks.front()));
                tasks.pop_front();

                // unlock during the task
                lock.unlock();
                task();
                lock.lock();
            }
        }

        // "do gui work"
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
}

注释:

  1. 我(一直)在学习,所以我的代码很可能不是很好。不过这个概念至少是合理的。

  2. std::async返回值的析构函数(a std::future<> )将阻塞,直到使用 std::async 启动操作为止完成(参见 std::async ),因此等待 one_off 中的任务结果(正如我在示例中所做的那样)可能不是一个好主意。

  3. 您可能希望(至少我愿意)创建自己的线程安全 MessageQueue 类型以提高代码可读性/可维护性/等等等等。

  4. 我发誓我还想指出一件事,但现在我想不起来了。

完整示例

#include <atomic>
#include <chrono>
#include <deque>
#include <iostream>
#include <mutex>
#include <future>
#include <thread>


// shared stuff:
std::deque<std::packaged_task<void()>> tasks;
std::mutex tasks_mutex;
std::atomic<bool> gui_running;


void message()
{
   std::cout << std::this_thread::get_id() << std::endl;
}


void one_off()
{
    std::packaged_task<void()> task(message);
    std::future<void> result = task.get_future();

    {
        std::lock_guard<std::mutex> lock(tasks_mutex);
        tasks.push_back(std::move(task));
    }

    // wait on result
    result.get();
}


void gui_thread()
{
    std::cout << "gui thread: "; message();

    while (gui_running) {
        // process messages
        {
            std::unique_lock<std::mutex> lock(tasks_mutex);
            while (!tasks.empty()) {
                auto task(std::move(tasks.front()));
                tasks.pop_front();

                // unlock during the task
                lock.unlock();
                task();
                lock.lock();
            }
        }

        // "do gui work"
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
}


int main()
{
    gui_running = true;

    std::cout << "main thread: "; message();
    std::thread gt(gui_thread);

    for (unsigned i = 0; i < 5; ++i) {
        // note:
        // these will be launched sequentially because result's
        // destructor will block until one_off completes
        auto result = std::async(std::launch::async, one_off);

        // maybe do something with result if it is not void
    }

    // the for loop will not complete until all the tasks have been
    // processed by gui_thread

    // ...

    // cleanup
    gui_running = false;
    gt.join();
}

数据输出

$ ./messages
main thread: 140299226687296
gui thread: 140299210073856
140299210073856
140299210073856
140299210073856
140299210073856
140299210073856

关于C++ std::async 在主线程上运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17354260/

相关文章:

c++ - Objective-C 中无法识别的函数

c++ - 如何使用仅使用其中一个 vector 的条件以相同方式对两个 vector 进行排序?

python - 我的Python多线程代码是否受到全局解释器锁的影响

c# - 如何使用 TPL 和 TaskScheduler 编写单元测试

asynchronous - 如何理解 Kotlin 协程?

c++ - 使用 QMake 制作独立的 OpenCV 应用程序

c++ - 我的容器类中应该允许多少整数?

python - 将 win32com 与多线程一起使用

c - 防止可能的数据竞争情况

c# - 什么时候应该使用 Task.Run()?