c++ OpenMP 关键:"one-way"锁定?
c++ OpenMP critical: "one-way" locking?
考虑以下串行函数。 当我并行化代码时,每个线程都会从并行区域内调用此函数(未显示(。 我正在尝试使这个线程安全且高效(快速(。
float get_stored_value__or__calculate_if_does_not_yet_exist( int A )
{
static std::map<int, float> my_map;
std::map::iterator it_find = my_map.find(A); //many threads do this often.
bool found_A = it_find != my_map.end();
if (found_A)
{
return it_find->second;
}
else
{
float result_for_A = calculate_value(A); //should only be done once, really.
my_map[A] = result_for_A;
return result_for_A;
}
}
几乎每次调用此函数时,线程都会成功"找到"其"A"的存储值(无论它是什么(。 每隔一段时间,当调用"新A"时,必须计算和存储一个值。
那么我应该把#pragma omp critical
放在哪里呢?
虽然很容易,但围绕所有这些进行#pragma omp critical
是非常低效的,因为每个线程都会不断执行此操作,并且通常是只读情况。
有没有办法实现"单向"critical
,或"单向"lock
例程? 也就是说,上述涉及迭代器的操作只应在写入else
语句中的my_map
时"锁定"。 但是多个线程应该能够同时执行.find
调用。
我希望我说得有道理。谢谢。
根据堆栈溢出上的此链接,插入std::map
不会使迭代器失效。 end()
迭代器也是如此。 这是一个支持链接。
不幸的是,如果您不使用关键部分,插入可能会发生多次。 此外,由于您的 calculate_value
例程的计算成本可能很高,因此您必须锁定以避免此 else
子句以相同的值 A
操作两次,然后插入两次。
下面是一个示例函数,您可以在其中复制这种不正确的多次插入:
void testFunc(std::map<int,float> &theMap, int i)
{
std::map<int,float>::iterator ite = theMap.find(i);
if(ite == theMap.end())
{
theMap[i] = 3.14 * i * i;
}
}
然后像这样称呼:
std::map<int,float> myMap;
int i;
#pragma omp parallel for
for(i=1;i<=100000;++i)
{
testFunc(myMap,i % 100);
}
if(myMap.size() != 100)
{
std::cout << "Problem!" << std::endl;
}
编辑:编辑以纠正厄勒版本中的错误。
OpenMP 是用于自动循环并行化的编译器"工具",而不是线程通信或同步库;因此它没有复杂的互斥锁,如读/写互斥锁:在写入时获取锁,但在读取时不获取锁。
下面是一个实现示例。
无论如何,克里斯A.的回答比我的要好:)
虽然@ChrisA的答案可能会解决你的问题,但我会把我的答案留在这里,以防将来的搜索者发现它有用。
如果您愿意,可以给#pragma omp critical
部分一个name
。然后,具有该名称的任何部分都被视为相同的关键部分。如果这是您想要做的,您可以轻松地使方法的一小部分变得至关重要。
#pragma omp critical map_protect
{
std::map::iterator it_find = my_map.find(A); //many threads do this often.
bool found_A = it_find != my_map.end();
}
。
#pragma omp critical map_protect
{
float result_for_A = calculate_value(A); //should only be done once, really.
my_map[A] = result_for_A;
}
#pragma omp atomic
和 #pragma omp flush
指令也可能有用。
atomic
会导致对内存位置(在指令前面的表达式中的左值(的写入始终是原子的。
flush
确保预期可供所有线程使用的任何内存实际上都写入所有线程,而不是存储在处理器缓存中,并且在应有的位置不可用。
- 如何找到锁定Linux futex的C++行
- G锁定铸造到基础上会释放模拟行为
- 如何检查线程是否锁定
- 如何在C++中找到active directory中禁用和锁定的窗口帐户
- 我应该在锁定TBitmap画布后解锁它吗
- C++ 11 中的锁定是否保证访问数据的新鲜度?
- 在两个线程上读/写 64 位,无互斥/锁定/原子
- 如何在实时应用程序中锁定线程
- 在 lambda 中锁定 std::shared_ptr 的复制操作
- 使用简单两相锁定的并发程序
- 锁定来自其他线程的类成员
- 他们如何将红外锁定像素转换为镜头前方 1m 的正常平面上的位置
- 同一互斥锁顺序上的锁定和解锁是否一致?
- 共享内存的升压容器是否实现锁定?
- 当只有一个线程主要使用该对象而其他线程很少使用它时,如何最小化该对象的互斥锁锁定?
- 如何在 x86 处理器上实现"锁定添加"
- MCS 锁定实现的问题
- c++ OpenMP 关键:"one-way"锁定?
- 优化算法以检查"Whether for a given directed graph there is only one way to sort the graph using topological
- One-way SOCK_STREAM