首页 > 解决方案 > 自定义节流器中的无限循环场景(竞争条件?)

问题描述

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

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

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

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

这种情况怎么会发生?有什么更好的实现建议(带有 m_ 前缀的变量意味着类变量,m_throttlingTime 和 m_isThrottling 是静态类变量)?

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

标签: c++concurrencythrottling

解决方案


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

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

使固定 :

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

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


推荐阅读