[英]How to use `std::async` to call a function in a mutex protected loop?
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
,可用于获取返回的值(启动的函数应返回某值)。 但是,由于您不存储将来,因此在任务启动后会立即销毁它。 不幸的是,在这种情况下,析构函数会阻塞直到调用完成。
如果满足以下所有条件,则[std :: future ::〜future()]可能会阻塞:共享状态是通过调用std :: async创建的,该共享状态尚未准备好,这是最后一个参考到共享状态。
( 报价 )很多人都表示无奈,由于这个事实,这就是它是如何通过标准的设置。
因此,您要做的就是存储std::future
(以向量或其他方式),直到全部启动。
您当然可以在保持互斥锁的同时调用std::async
。 缺点是调用std::async
会花费一些时间,从而增加了锁定该互斥锁的时间,从而降低了并行度。
按住锁时复制该向量可能会更便宜。 然后释放互斥锁并异步处理副本。
您的优化目标是最大程度地减少互斥锁被锁定的时间,以及可能花费在该功能上的时间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.