【问题标题】:Mutex when returning object value返回对象值时的互斥锁
【发布时间】:2013-05-07 12:52:22
【问题描述】:

如果我了解 C++ 编译器如何处理局部变量,那么 IsShutdownInProgress() 不需要任何锁定,因为 shutdownInProgress 静态变量将被放置在堆栈上。我说的对吗?

class MyClass
{
    private:
        // Irrelevant code commented away
        static pthread_mutex_t mutex;
        static bool shutdownInProgress;
    public:
        static void ShutdownIsInProgress()
        {
            pthread_mutex_lock(mutex);
            shutdownInProgress = true;                  
            pthread_mutex_unlock(mutex);
        }

        static bool IsShutdownInProgress()
        {
            // pthread_mutex_lock(mutex);
            // pthread_mutex_unlock(mutex);
            return shutdownInProgress;
        }
}

【问题讨论】:

    标签: c++ multithreading pthreads mutex


    【解决方案1】:

    我说的对吗?

    没有。这将使它的副本返回;但是读取它以在不同步的情况下制作该副本将导致 数据竞争,具有未定义的行为。您需要在互斥锁锁定的情况下制作它的本地副本:

    static bool IsShutdownInProgress()
    {
        pthread_mutex_lock(mutex);
        bool result = shutdownInProgress;
        pthread_mutex_unlock(mutex);
        return result;
    }
    

    或者,使用不易出错的 RAII 锁类型:

    static bool IsShutdownInProgress()
    {
        lock_guard lock(mutex);
        return shutdownInProgress;
    }
    

    在 C++11 中,您可能会考虑使用std::atomic<bool>,以便更方便、更高效地从多个线程访问简单类型。

    【讨论】:

      【解决方案2】:

      竞争条件与变量位于堆上还是栈上无关。竞争条件是当一个线程正在修改一个变量(内存位置)而另一个线程正在读取或修改同一个变量时。无法保证 bool 的修改是原子的,因此发布的代码具有竞争条件,因此具有未定义的行为。

      解决方法是在持有互斥锁时存储bool 的值并返回变量:

      static bool IsShutdownInProgress()
      {
          pthread_mutex_lock(&mutex);
          bool result = shutdownInProgress;
          pthread_mutex_unlock(&mutex);
          return result;
      }
      

      c++11 引入了可以使用的std::mutexstd::lock_guard,使用lock_guard 将避免需要临时变量来存储bool 值以供返回:

      static std::mutex mtx_;
      static bool IsShutdownInProgress()
      {
          std::lock_guard<std::mutex> lk(mtx_);
          return shutdownInProgress;
      }
      

      c++11 还引入了std::atomic&lt;&gt;,这将确保修改是原子的并避免需要显式锁定:

      static std::atomic<bool> shutdownInProgress;
      static bool IsShutdownInProgress()
      {
          return shutdownInProgress;
      }
      

      如果 c++11 对 boost::atomic 不可用是在 v1.53.0 中引入的,并且 boost 也有等效的 boost::mutex and boost::lock_guard

      【讨论】:

        【解决方案3】:

        是的,它需要一个锁

        C++11 的内存模型表明,如果任何线程在写入值的同时另一个线程正在读取它,那么您就会发生数据竞争。这是因为读取和/或写入都可能不是原子的。

        在这种情况下,您将从函数返回一个局部变量,但要获得该局部变量,编译器需要复制 shutdownInProgress 中的值,该值可能同时被另一个调用 ShutdownIsInProgress() 的线程更改。

        解决这个问题的一个简单方法是使shutdownInProgress 成为原子:

        static std::atomic<bool> shutdownInProgress;
        

        如果你把它变成原子的,你就不需要任何锁来实现这两个函数

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-02-23
          • 1970-01-01
          • 2018-05-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多