Sel*_*_va 0 c++ multithreading mutex vector thread-safety
我有一个共享向量,可通过两个线程访问。
线程A的函数推入向量,线程B的函数将向量完全交换以进行处理。
MovetoVec(PInfo* pInfo)
{
while(1)
{
if(GetSwitch())
{
swapBucket->push_back(pInfo);
toggles = true;
break;
}
else if(pInfo->tryMove == 5)
{
delete pInfo;
break;
}
pInfo->tryMove++;
Sleep(25);
}
}
Run Code Online (Sandbox Code Playgroud)
线程A试图使原子布尔值toggles变为true并推入向量。(上面的MoveToVec函数将被许多线程调用)。函数GetSwitch定义为
GetSwitch()
{
if(toggles)
{
toggles = false;
return TRUE;
}
else
return FALSE;
}
Run Code Online (Sandbox Code Playgroud)
toggles 这是atomic_bool,线程B中另一个交换向量的函数是
GetClassObj(vector<ProfiledInfo*>* toSwaps)
{
if(GetSwitch())
{
toSwaps->swap(*swapBucket);
toggles = true;
}
}
Run Code Online (Sandbox Code Playgroud)
如果GetSwitch返回false,则threadB不执行任何操作。在这里我不使用任何锁定。它在大多数情况下都有效。但是有时pInfo,swapBucket 中的对象之一为NULL。我知道这是因为同步不良。
我遵循这种类型的GetSwitch()逻辑只是为了忽略由锁定引起的开销。我应该放弃这个并返回互斥或关键部分的东西吗?
您的GetSwitch实现是错误的。多个线程有可能同时获取开关。
只有两个线程的这种情况的示例:
Thread 1 | Thread 2
--------------------------|--------------------------
if (toggles) |
| if (toggles)
toggles = false; |
| toggles = false;
Run Code Online (Sandbox Code Playgroud)
if-test和赋值不是原子操作,因此不能单独用于同步线程。
如果要使用原子布尔作为同步手段,则需要在一个原子操作中比较并交换该值。幸运的是,C ++提供了一种称为的操作std::compare_exchange,该操作有很弱的作用(弱的操作可能会虚假地失败,但在循环中调用时会便宜一些)。
使用此操作,您的GetSwitch方法将变为:
bool GetSwitch()
{
bool expected = true; // The value we expect 'toggles' to have
bool desired = false; // The value we want 'toggles' to get
// Check if 'toggles' is as expected, and if it is, update it to the desired value
bool result = toggles.compare_exchange_strong(&expected, desired);
// The result of the compare_exchange is true if the value was updated and false if it was not
return result;
}
Run Code Online (Sandbox Code Playgroud)
这将确保自动比较和更新值。
请注意,C ++标准不保证原子布尔值是无锁的。在您的情况下,您也可以使用std::atomic_flag标准保证无锁的产品!仔细阅读该示例,它的工作原理与原子变量略有不同。
正如您正在尝试做的那样,编写无锁代码非常复杂且容易出错。
我的建议是先编写带锁的代码,并确保它是100%正确的。互斥体实际上出奇地快,因此在大多数情况下性能应该还可以。良好的锁定性能阅读:http://preshing.com/20111118/locks-arent-slow-lock-contention-is
仅在分析了代码并确信锁会影响性能之后,才应尝试编写无锁的代码。然后再分析一次,因为无锁代码不一定更快。