首先,G_LOCK_DEFINE 所做的只是创建一个 GMutex 变量,其名称编码了它所保护的变量的名称,例如G_LOCK_DEFINE(mSomeCounter) 变为 GMutex g__mSomeCounter_lock;。因此我们可以将您的代码扩展为:
class CSomeClass {
private:
gulong mSomeCounter;
GMutex g__mSomeCounter_lock;
public:
CSomeClass ();
};
CSomeClass::CSomeClass()
{
g_mutex_lock(&g__mSomeCounter_lock);
mSomeCounter = 0;
g_mutex_unlock(&g__mSomeCounter_lock);
}
这里的根本问题是您没有初始化类CSomeClass 的任何 成员。您将在构造函数中为其中的 一些 赋值,但绝对不会初始化它们。大括号中的赋值和使用初始化器是有区别的,比如:
CSomeClass::CSomeClass() : mSomeCounter(0)
因此,创建的、针对变量命名的互斥锁可能包含垃圾。 glib 代码中可能没有任何更改会导致这种情况发生,更有可能是对其他库的更改更改了您的应用程序的内存布局,从而发现了错误。
glib documentation 提示您需要 g_mutex_init 互斥锁:
已分配在堆栈上,或作为更大结构的一部分
您不需要g_mutex_init 互斥体:
不需要初始化已经静态分配的互斥锁
类实例几乎总是不是静态分配的。
您需要修复您的构造函数以确保它“正确”初始化互斥锁,例如:
CSomeClass::CSomeClass()
{
g_mutex_init(&G_LOCK_NAME(mSomeCounter));
G_LOCK(mSomeCounter);
mSomeCounter = 0;
G_UNLOCK(mSomeCounter);
}
TBH,我会将互斥锁放入类持有者中,并将其作为其中的一部分进行初始化,而不是按照您的方式进行初始化,以确保它作为标准 C++ 的一部分被初始化、锁定和解锁RAII 语义。
如果您使用小型主存根,例如:
main() {
{ CSomeClass class1; }
{ CSomeClass class2; }
{ CSomeClass class3; }
}
还有你的代码,无论如何它很有可能会挂起。 (我的 mac 使示例崩溃:GLib (gthread-posix.c): Unexpected error from C library during 'pthread_mutex_lock': Invalid argument. Aborting.。
一些简单的,例如,非生产包装器来帮助处理 RAII:
class CGMutex {
GMutex mutex;
public:
CGMutex() {
g_mutex_init(&mutex);
}
~CGMutex() {
g_mutex_clear(&mutex);
}
GMutex *operator&() {
return &mutex;
}
};
class CGMutexLocker {
CGMutex &mRef;
public:
CGMutexLocker(CGMutex &mutex) : mRef(mutex) {
g_mutex_lock(&mRef);
}
~CGMutexLocker() {
g_mutex_unlock(&mRef);
}
};
class CSomeClass {
private:
gulong mSomeCounter;
CGMutex mSomeCounterLock;
public:
CSomeClass ();
};
CSomeClass::CSomeClass()
{
CGMutexLocker locker(mSomeCounterLock); // lock the mutex using the locker
mSomeCounter = 0;
}
mSomeCounter 初始化确保计数器被初始化,否则会产生垃圾。