返回对象值时互斥

Mutex when returning object value

本文关键字:对象 返回      更新时间:2023-10-16

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

我说的对吗?

。这将使它的副本返回;但是在没有同步的情况下读取它来进行复制将产生数据竞争,并具有未定义的行为。您需要在锁住互斥锁的情况下创建一个本地副本:

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

争用条件与变量位于堆上还是堆栈上无关。争用条件是指一个线程正在修改一个变量(内存位置),而另一个线程正在读取或修改同一个变量。不能保证对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;
}

如果c++11不可用,则boost::atomic在v1.53.0中引入,boost也有等效的boost::mutexboost::lock_guard

是的,它需要一个锁

c++ 11的内存模型指出,如果一个线程在写一个值的同时另一个线程在读这个值,那么你就有一个数据竞争。这是因为读操作和/或写操作可能都不是原子操作。

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

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

static std::atomic<bool> shutdownInProgress;

如果你让它原子化,你不需要任何锁对于任何函数