c++11 线程与异步

问题描述 投票:0回答:2

考虑以下两个代码片段,我试图在其中启动 10000 个线程:

片段1

    std::array<std::future<void>, 10000> furArr_;
    try
    {
        size_t index = 0;
        for (auto & fut : furArr_)
        {
            std::cout << "Created thread # " << index++ << std::endl;
            fut = std::async(std::launch::async, fun);
        }
    }
    catch (std::system_error & ex)
    {
        std::string str = ex.what();
        std::cout << "Caught : " << str.c_str() << std::endl;
    }
    // I will call get afterwards, still 10000 threads should be active by now assuming "fun" is time consuming

片段2

    std::array<std::thread, 10000> threadArr;
    try
    {
        size_t index = 0;
        for (auto & thr : threadArr)
        {
            std::cout << "Created thread # " << index++ << std::endl;
            thr = std::thread(fun);
        }
    }
    catch (std::system_error & ex)
    {
        std::string str = ex.what();
        std::cout << "Caught : " << str.c_str() << std::endl;
    }

第一个案例总是成功的。即我可以创建 10000 个线程,然后我必须等待所有线程完成。在第二种情况下,在创建 1600 多个线程后,我几乎总是会遇到异常(“资源不可用,请重试”)。

使用 std::launch::async 的启动策略,我认为这两个片段的行为应该相同。具有 async 启动策略的 std::async 与显式使用 std::thread 启动线程有何不同?

我在Windows 10,VS2015上,二进制文件是在x86发布模式下构建的。

multithreading c++11 stdthread stdasync
2个回答
8
投票

首先,感谢Igor Tandetnik为我提供了这个答案的方向。

当我们使用

std::async
(使用异步启动策略)时,我们会说:

“我想在单独的线程上完成这项工作”。

当我们使用

std::thread
时,我们是在说:

“我想在新线程上完成这项工作”。

细微的差别意味着

async
(通常)使用线程池实现。这意味着,如果我们多次使用
async
调用一个方法,该方法内的线程 ID 通常会重复,即
async
会将多个作业分配给池中的同一组线程。而对于
std::thread
,它永远不会。

这种差异意味着,与使用

async
async
启动策略相比,显式启动线程可能会消耗更多资源(因此是例外)。


0
投票

当我们使用 std::async (带有异步启动策略)时,我们是在说:

“我想在单独的线程上完成这项工作”。

这并非适用于所有实现。

典型的实现实际上会使用线程池

Igor 对典型实现应该做什么的假设是错误的。

std::launch::async

被指定为使得实现可以在最简单的情况下创建新线程。 libstdc++ 和 libc++ 执行此操作。 MSVC++ 使用线程池,但这并不意味着它是一个典型的实现。

看看这些讨论 异步最终会创建新线程 以及这个,尽管它可能与您的查询不直接相关

© www.soinside.com 2019 - 2024. All rights reserved.