避免在单个线程中出现死锁

hfh*_*hc2 4 c++ multithreading glib

我有以下问题:我有一个类需要保护免受不同线程的同时访问.该类有两个方法:lock()和unlock()using(g_mutex_lock/ g_mutex_unlockwith per-object GMutex).现在锁定方法如下所示:

void Object::method()
{
    lock();
    // do stuff modifying the object
    unlock();
}
Run Code Online (Sandbox Code Playgroud)

现在让我们假设我有两个这种类型的mwthods,method1()以及method2()我称之为此起彼伏:

object.method1();
// but what if some other thread modifies object in between
object.method2();
Run Code Online (Sandbox Code Playgroud)

我尝试在此块之前锁定对象并再次解锁它,但在这种情况下,即使使用单个线程也会出现死锁,因为GMutex它不知道它已被同一个线程锁定.解决方案是修改方法以接受附加bool以确定对象是否已被锁定.但是有更优雅的概念吗?或者这总是关于设计概念的缺点?

Mig*_*uel 6

其他响应和注释中提到的递归互斥解决方案可以正常工作,但根据我的经验,它会导致代码更难维护,因为一旦你切换到递归互斥锁,就很容易滥用它并锁定所有地点.

相反,我更喜欢重新组织代码,以便锁定一次就足够了.在您的示例中,我将按如下方式定义类:

class Object {
public:
    void method1() {
        GMutexLock scopeLock(&lock);
        method1_locked();
    }
    void method2() {
        GMutexLock scopeLock(&lock);
        method2_locked();
    }
    void method1_and_2() {
        GMutexLock scopeLock(&lock);
        method1_locked();
        method2_locked();
    }

private:
    void method1_locked();
    void method2_locked();

    GMutex lock;
};
Run Code Online (Sandbox Code Playgroud)

方法的"锁定"版本是私有的,因此只能从类中访问它们.如果没有采取锁定,该类负责从不调用它们.

从外部,您可以选择三种方法来调用,具体取决于您要运行的方法.

请注意,我所做的另一项改进是不使用显式锁定原语,而是间接使用范围来锁定和解锁.这是做什么的GMutexLock.此类的示例实现如下:

class GMutexLock {
private:
    GMutex* m;

    GMutexLock(const GMutexLock &mlock); // not allowed
    GMutexLock &operator=(const GMutexLock &); // not allowed

public:
    GMutexLock(GMutex* mutex) {
        m = mutex;
        g_mutex_lock(m);
    }

    ~GMutexLock() {
        g_mutex_unlock(m);
    }
};
Run Code Online (Sandbox Code Playgroud)