简体   繁体   English

共享向量与原子布尔同步

[英]Shared vector Synchronization with an atomic boolean

I am having a shared vector which gets accessed by two threads. 我有一个共享向量,可通过两个线程访问。

A function from thread A pushs into the vector and a function from thread B swaps the vector completely for processing. 线程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);
        }
    }

The thread A tries to get atomic boolean toggles to true and pushes into vector.( the above MoveToVec function will be called by many number of threads ). 线程A尝试获取原子布尔值toggles为true并推入向量。( 上面的MoveToVec函数将被许多线程调用 )。 The function GetSwitch is defined as 函数GetSwitch定义为

GetSwitch()
{
   if(toggles)
   {
      toggles = false;
      return TRUE;
   }
   else
        return FALSE;
}

toggles here is atomic_bool.And the another function from thread B that swaps the vector is toggles这里toggles是atomic_bool,而线程B中另一个交换向量的函数是

    GetClassObj(vector<ProfiledInfo*>* toSwaps)
    {
        if(GetSwitch())
        {
            toSwaps->swap(*swapBucket);
            toggles = true;
        }
    }

If GetSwitch returns false then the threadB does nothing. 如果GetSwitch返回false,则threadB不执行任何操作。 Here i dint use any locking. 在这里我不使用任何锁定。 It works in most of the cases. 它在大多数情况下都有效。 But some time one of the pInfo objects in swapBucket is NULL. 但是有时候,swapBucket中的pInfo对象之一为NULL。 I got to know it is because of poor synchronization. 我知道这是因为同步不良。

I followed this type of GetSwitch() logic just to neglect the overhead caused by locking. 我遵循这种类型的GetSwitch()逻辑只是为了忽略由锁定引起的开销。 Should i drop this out and go back to mutex or critical section stuffs? 我应该放弃这个并返回互斥或关键部分的东西吗?

Your GetSwitch implementation is wrong. 您的GetSwitch实现是错误的。 It is possible for multiple threads to acquire the switch simultaneously. 多个线程有可能同时获取开关。

An example of such a scenario with just two threads: 只有两个线程的这种情况的示例:

 Thread 1                 | Thread 2
--------------------------|--------------------------
 if (toggles)             |
                          | if (toggles)
     toggles = false;     |
                          |     toggles = false;

The if-test and assignment are not an atomic operation and therefore cannot be used to synchronize threads on their own. if-test和赋值不是原子操作,因此不能单独用于同步线程。


If you want to use an atomic boolean as a means of synchronization, you need to compare and exchange the value in one atomic operation. 如果要使用原子布尔作为同步手段,则需要在一个原子操作中比较并交换该值。 Luckily, C++ provides such an operation called std::compare_exchange , which is available in a weak and strong flavor (the weak one may spuriously fail but is cheaper when called in a loop). 幸运的是,C ++提供了一种名为std::compare_exchange的操作,该操作有弱有力的功能(弱的功能可能会虚假地失败,但在循环中调用时会便宜一些)。

Using this operation, your GetSwitch method would become: 使用此操作,您的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;
}

This will ensure that comparing and updating the value happens atomically. 这将确保自动比较和更新值。

Note that the C++ standard does not guarantee an atomic boolean to be lock-free. 请注意,C ++标准不保证原子布尔值是无锁的。 In your case, you could also use std::atomic_flag which is guaranteed to be lock-free by the standard! 在您的情况下,您还可以使用std::atomic_flag ,它保证标准不会锁定! Carefully read the example though, it works a tad bit different than atomic variables. 仔细阅读该示例,它的工作原理与原子变量略有不同。


Writing lock-free code, as you are attempting to do, is quite complex and error-prone. 正如您正在尝试做的那样,编写无锁代码非常复杂且容易出错。

My advice would be to write the code with locks first and ensure it is 100% correct. 我的建议是先编写带锁的代码,并确保它是100%正确的。 Mutexes are actually surprisingly fast, so performance should be okay in most cases. 互斥体实际上出奇地快,因此在大多数情况下性能应该还可以。 A good read on lock performance: http://preshing.com/20111118/locks-arent-slow-lock-contention-is 良好的锁定性能阅读: http//preshing.com/20111118/locks-arent-slow-lock-contention-is

Only once you have profiled your code, and convinced yourself that the locks are impacting performance, you should attempt to write the code lock-free. 仅在分析了代码并确信锁会影响性能之后,才应尝试编写无锁的代码。 Then profile again because lock-free code is not necessarily faster. 然后再分析一次,因为无锁代码不一定更快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM