c++ - 如何使用 `std::async` 在互斥保护循环中调用函数?

标签 c++ multithreading c++14

vector<int> vecCustomers;
// populate vecCustomers

void funA()
{
    std::lock_guard<std::mutex> guard( _mutex ); // need lock here
    for(int i=0; i<vecCustomers.size(); ++i)
    {
        funB( vecCustomers[i] ); // can I run this asynchronously       
    }
}

void funB(int i)
{
    // do something here
}

问题> funA 访问关键资源,它使用锁来保护资源。 funB 不使用任何关键资源,也不需要互斥锁。有没有一种方法可以利用 std::async 以便我可以调用 funB 并立即返回以准备在循环内调用下一个 funB?此外,在函数返回之前,funB 的所有任务必须完成。

谢谢

==更新==

我根据建议编写了以下代码。现在,新问题是为什么所有线程都被第一个线程阻塞?

输出总是如下:

From[0]:H0 << why this thread blocks all others?
From[1]:H1
From[2]:H2
From[3]:H3
From[4]:H4


#include <vector>
#include <future>
#include <mutex>
#include <string>
#include <iostream>
#include <chrono>
using namespace std;

struct ClassA
{
    ClassA()
    {
        vecStr.push_back( "H0" );
        vecStr.push_back( "H1" );
        vecStr.push_back( "H2" );
        vecStr.push_back( "H3" );
        vecStr.push_back( "H4" );
    }

    void start()
    {

        for ( int i = 0; i < 5; ++i )
        {
            std::unique_lock<std::mutex> guard( _mutex );
            std::string strCopy = vecStr[i];

            guard.unlock();
            std::async( std::launch::async, &ClassA::PrintString, this, i, strCopy );
            //PrintString( i, vecStr[i] );
            guard.lock();
        }
    }

    void PrintString( int i, const string& str) const
    {            
        if ( i == 0 )
            std::this_thread::sleep_for( std::chrono::seconds( 10 ) );
        cout << "From[" << i << "]:" << str << endl;
    }

    mutex _mutex;
    vector<string> vecStr;
};

int main()
{
    ClassA ca;

    ca.start();

    return 0;
}

===更新 2===

#include <vector>
#include <future>
#include <mutex>
#include <string>
#include <iostream>
#include <chrono>
using namespace std;

struct ClassA
{
    ClassA()
    {
        vecStr.push_back( "H0" );
        vecStr.push_back( "H1" );
        vecStr.push_back( "H2" );
        vecStr.push_back( "H3" );
        vecStr.push_back( "H4" );
    }

    void start()
    {
        std::vector<std::future<void>> result;
        for ( int i = 0; i < 5; ++i )
        {
            std::unique_lock<std::mutex> guard( _mutex );
            std::string strCopy = vecStr[i];

            guard.unlock();
            result.push_back( std::async( std::launch::async, &ClassA::PrintString, this, i, strCopy ) );
            //PrintString( i, vecStr[i] );
        }

        for(auto &e : result) 
        {
            e.get();
        }
    }

    void PrintString( int i, const string& str) const
    {            
        static std::mutex m;
        std::unique_lock<std::mutex> _(m);

        if ( i == 0 )
        {
            cout << "From[" << i << "]:" << str << " sleep for a while" << endl;
            _.unlock();
            std::this_thread::sleep_for( std::chrono::seconds( 10 ) );
        }
        else
            cout << "From[" << i << "]:" << str << endl;
    }

    mutex _mutex;
    vector<string> vecStr;
};

int main()
{
    ClassA ca;

    ca.start();

    return 0;
}

最佳答案

您看到调用按顺序执行的主要原因是您没有以任何方式利用并行性(等等,什么?但是...)。让我解释一下

std::async 不仅启动一个异步运行的任务,它还返回一个 std::future 可用于获取返回值(启动的函数应该返回一些东西)。但是,因为您不存储 future ,所以它会在任务启动后立即销毁。不幸的是,在这种情况下,析构函数会阻塞,直到调用完成。

[std::future::~future()] may block if all of the following are true: the shared state was created by a call to std::async, the shared state is not yet ready, and this was the last reference to the shared state.

( quote ) 许多人对此表示沮丧,但这就是标准设定的方式。

所以您需要做的是存储 std::future(在 vector 或其他东西中)直到所有都启动。

关于c++ - 如何使用 `std::async` 在互斥保护循环中调用函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36920579/

相关文章:

c++ - SFINAE 优雅地检查 "template template class"(在模板参数中)

c++ - 为什么代码创建错误的二叉搜索树

c++ - 用 vector 表示和遍历一棵 n 叉树

c++ - gmock 忽略 "interesting"函数调用

java - 图片加载时间过长?

c# - 调用Parallel.Foreach中的方法并将结果保存到线程安全列表中

c++ - GCC 拒绝使用 enum-base 的简单声明; clang 接受它——这是正确的吗?

c++ - `std::bind()` 标准库算法如何实现?

c++ - 可以在没有 typedef 的情况下访问模板外部的模板参数吗?

c# - 优先级最低的线程被调用更多次