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

q09*_*987 2 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
}
Run Code Online (Sandbox Code Playgroud)

问题> 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;
}
Run Code Online (Sandbox Code Playgroud)

===更新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;
}
Run Code Online (Sandbox Code Playgroud)

kmd*_*eko 5

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

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

如果满足以下所有条件,则[std :: future ::〜future()]可能会阻塞:共享状态是通过调用std :: async创建的,共享状态尚未准备好,这是最后一个参考到共享状态。

报价)很多人都表示无奈,由于这个事实,这就是它是如何通过标准的设置。

因此,您要做的就是将std::futures(以向量或某种方式存储)存储,直到全部启动。