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

时间:2013-06-27 22:25:43

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

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

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

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

2 个答案:

答案 0 :(得分:11)

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

短版

拥有共享的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::asyncstd::future<>)返回值的析构函数将阻塞,直到std::async启动的操作完成(请参阅std::async),等待在one_off中的任务结果(就像我在我的例子中所做的那样)可能不是一个好主意。

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

  4. 我发誓还有一件事我想指出,但现在它已经逃脱了我。

  5. 完整示例

    #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
    

答案 1 :(得分:0)

您在寻找std::launch::deferred吗?将此参数传递给std :: async会在第一次调用get()函数时在调用线程上执行该任务。

相关问题