自定义节流器中的无限循环场景(竞争条件?)

Infinite loop scenario in custom throttler (race condition?)

我编写了一个自定义节流器来处理某些客户端(正在进行外部调用)出现退避异常并且需要在进行另一个 API 调用之前休眠的情况。

我有一个内存转储,其中有一个奇怪的场景:卡在无限循环中,尽管我看不出有什么原因。 此应用程序有许多线程,所有客户端调用都使用以下代码进行了限制。 调用一些 API 是这样完成的:

bool res = DoSomeAction([&]{ /* call client m_client.callAPI()*/ return true}

内存转储显示只有 1 个线程在工作(通常有 10 个),并且 m_isThrottling 设置为 true,因此整个应用程序永远 运行。

怎么会出现这种情况?任何更好实施的建议(带有 m_ 前缀的变量表示 class 变量,m_throttlingTime 和 m_isThrottling 是静态 class 变量)?

template<typename T>
bool ThrottlerClass::DoSomeAction(T && lambda)
{
    for (int retriesCount = 3; retriesCount > 0; --retriesCount)
    {
        while (m_isThrottling) //dump is stuck here
        {
            Sleep(10000);
        }

        try
        {
            return lambda();
        }
        catch (const std::exception& ex)
        {
            int time = m_client->GetThrottlingTimeMS(); //the client got exception making API call and saves it

            if (time > 0)
            {
                ExclusiveLock lock(&m_throttlingMutex); //custom scope mutex
                m_isThrottling = true;
                if (time > m_throttlingTime) 
                    m_throttlingTime = time;
            }

            if (m_throttlingTime > 0)
            {
                Sleep(m_throttlingTime);

                {
                    ExclusiveLock lock(&m_throttlingMutex);
                    m_isThrottling = false;
                    m_throttlingTime = 0;
                }
            }

            continue;
        }
    }

    return false;
}

无法保证您线程中 m_isTrhottling 的值将永远获得其真实值。事实上,每个线程都有自己的世界观,所以在另一个线程的视图中,写入 m_isThrottling,值是 true,但是你的第三个线程看到了不同的画面。

锁是线程世界观同步的一种方式。如果您使用锁而不是循环,该值将在您的等待线程中更新。

修复:

  • 要么使用锁
  • std::atomic<bool>也保证了同步。

澄清编辑:class变量上下文中的关键字static与内存模型无关。在这种情况下,关键字只是声明该变量属于 class 而不是任何特定对象。这与线程世界观(或缺乏)的同步完全无关。 static 与线程相关的唯一地方是函数内部的静态变量 初始化 ,但事实并非如此(既不是函数静态变量,也不是初始化)