返回对象值时的互斥锁

时间:2013-05-13 13:09:40

标签: c++ multithreading pthreads mutex

如果我理解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;
        }
}

3 个答案:

答案 0 :(得分:12)

  

我说错了吗?

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

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>从多个线程访问简单类型,以便更方便,也许更有效。

答案 1 :(得分:3)

竞争条件与变量是位于堆上还是堆栈上无关。竞争条件是一个线程正在修改变量(内存位置)而另一个线程正在读取或修改同一个变量。无法保证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<>,它将确保修改是原子的,并且无需显式锁定:

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

如果{+ 3}}的c ++ 11不可用,则在v1.53.0中引入,而且boost也具有等效的boost::atomic

答案 2 :(得分:1)

是的,需要锁定

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

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

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

static std::atomic<bool> shutdownInProgress;

如果你使它成为原子,你根本不需要任何锁定