c++ - 共享 vector 与原子 bool 同步

标签 c++ multithreading vector thread-safety mutex

我有一个由两个线程访问的共享 vector 。

线程 A 的一个函数压入 vector ,线程 B 的一个函数完全交换 vector 以进行处理。

    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);
        }
    }

线程 A 尝试将原子 bool 值 切换 为 true 并插入 vector。(上面的 MoveToVec 函数将被许多线程调用)。函数 GetSwitch 定义为

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

toggles 这里是 atomic_bool。另一个来自线程 B 的交换 vector 的函数是

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

如果 GetSwitch 返回 false,threadB 什么都不做。在这里我不使用任何锁定。它适用于大多数情况。但有时 swapBucket 中的 pInfo 对象之一为 NULL。我知道这是因为同步不良。

我遵循这种类型的 GetSwitch() 逻辑只是为了忽略锁定引起的开销。我应该放弃这个并回到互斥锁或关键部分的东西吗?

最佳答案

您的 GetSwitch 实现有误。多个线程可以同时获取开关。

只有两个线程的这种情况的示例:

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

if-test 和赋值不是原子操作,因此不能单独用于同步线程。


如果要使用原子 bool 值作为同步手段,则需要在一个原子操作中比较和交换值。幸运的是,C++ 提供了这样一个名为 std::compare_exchange 的操作。 ,它有 weak 和 strong 两种风格(弱的可能会虚假地失败,但在循环中调用时更便宜)。

使用此操作,您的 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;
}

这将确保以原子方式比较和更新值。

请注意,C++ 标准不保证原子 bool 值是无锁的。在你的情况下,你也可以使用 std::atomic_flag标准保证是无锁的!不过请仔细阅读示例,它的工作方式与原子变量略有不同。


正如您尝试做的那样,编写无锁代码非常复杂且容易出错。

我的建议是先写带锁的代码,并确保它 100% 正确。互斥量实际上出奇地快,因此在大多数情况下性能应该没问题。关于锁性能的好读物:http://preshing.com/20111118/locks-arent-slow-lock-contention-is

只有在分析了代码并确信锁会影响性能后,您才应该尝试编写无锁代码。然后再次分析,因为无锁代码不一定更快。

关于c++ - 共享 vector 与原子 bool 同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44882289/

相关文章:

c++ - strcmp 和复制的 char 数据的段错误

具有多个客户端的 Java Socket 编程

java - 如何保持 executorService 运行?

c++ - 如何初始化数组 vector

c++ - 使用 free() 释放 new 分配的内存空间

c++ - C++03中如何判断函数是否返回引用?

c++ - 如何从 glm::mat4 中读取值

multithreading - 在Linux内核中,以下方式创建实时kthread是否正确?

c++ - 我如何从文本文件中读取数据并将其推回 vector ?

c++ - 当我执行 std::vector = std::vector 时,std::vector 的旧值会发生什么