G_LOCK 行为从 glib 2.46 更改为 glib 2.48?
G_LOCK behavior changed from glib 2.46 to glib 2.48?
我正在查看一段代码,它直到最近才起作用。基本上,我有一个 C++ class,其中我用 G_LOCK_DEFINE 宏保护一个变量。
class CSomeClass {
private:
gulong mSomeCounter;
G_LOCK_DEFINE(mSomeCounter);
public:
CSomeClass ();
}
构造函数在单独的 .cpp 文件中实现。
CSomeClass::CSomeClass()
{
G_LOCK(mSomeCounter);
mSomeCounter = 0;
G_UNLOCK(mSomeCounter);
}
该变量在多个函数中被访问,但原理始终相同。现在,正如已经说过的,代码编译得很好,实际上在过去也 运行 完美无缺。现在,从最近开始,每当遇到 G_LOCK 命令时,我都会陷入僵局。为了调试,我已经将程序限制为只有一个线程,以排除逻辑错误。
我最近确实更新到 Ubuntu 16.04 beta,这将我的 glib 版本推到了 2.48.0-1ubuntu4。我已经检查了变更日志以获取有关 G_LOCK 的相关信息,但找不到任何信息。在最近的 glib 版本中使用 G_LOCK 宏时,有没有其他人注意到有趣的效果?我错过了这里的一些变化吗?
首先,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);
}
这里的根本问题是您没有初始化 class CSomeClass
的 any 成员。您将在构造函数中为其中的 一些 赋值,但绝对不会初始化它们。大括号中的赋值与使用初始化程序之间存在差异,例如:
CSomeClass::CSomeClass() : mSomeCounter(0)
因此,根据变量命名的互斥锁可能包含垃圾。 glib 代码中可能没有任何内容会导致这种情况发生,更可能是对其他库的更改改变了您应用程序的内存布局,从而发现了错误。
glib documentation 提示您需要 g_mutex_init
互斥锁:
that has been allocated on the stack, or as part of a larger structure
您不需要 g_mutex_init
互斥:
It is not necessary to initialize a mutex that has been statically allocated
Class 个实例几乎总是不是 静态分配的。
您需要修复构造函数以确保它初始化互斥量 'properly' 例如:
CSomeClass::CSomeClass()
{
g_mutex_init(&G_LOCK_NAME(mSomeCounter));
G_LOCK(mSomeCounter);
mSomeCounter = 0;
G_UNLOCK(mSomeCounter);
}
TBH,我会将互斥量放入 class 持有者中,并将其初始化为其中的一部分,而不是按照您的方式进行初始化,以确保它被初始化、锁定和解锁作为标准 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 初始化确保计数器得到初始化,否则会产生垃圾。
我正在查看一段代码,它直到最近才起作用。基本上,我有一个 C++ class,其中我用 G_LOCK_DEFINE 宏保护一个变量。
class CSomeClass {
private:
gulong mSomeCounter;
G_LOCK_DEFINE(mSomeCounter);
public:
CSomeClass ();
}
构造函数在单独的 .cpp 文件中实现。
CSomeClass::CSomeClass()
{
G_LOCK(mSomeCounter);
mSomeCounter = 0;
G_UNLOCK(mSomeCounter);
}
该变量在多个函数中被访问,但原理始终相同。现在,正如已经说过的,代码编译得很好,实际上在过去也 运行 完美无缺。现在,从最近开始,每当遇到 G_LOCK 命令时,我都会陷入僵局。为了调试,我已经将程序限制为只有一个线程,以排除逻辑错误。
我最近确实更新到 Ubuntu 16.04 beta,这将我的 glib 版本推到了 2.48.0-1ubuntu4。我已经检查了变更日志以获取有关 G_LOCK 的相关信息,但找不到任何信息。在最近的 glib 版本中使用 G_LOCK 宏时,有没有其他人注意到有趣的效果?我错过了这里的一些变化吗?
首先,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);
}
这里的根本问题是您没有初始化 class CSomeClass
的 any 成员。您将在构造函数中为其中的 一些 赋值,但绝对不会初始化它们。大括号中的赋值与使用初始化程序之间存在差异,例如:
CSomeClass::CSomeClass() : mSomeCounter(0)
因此,根据变量命名的互斥锁可能包含垃圾。 glib 代码中可能没有任何内容会导致这种情况发生,更可能是对其他库的更改改变了您应用程序的内存布局,从而发现了错误。
glib documentation 提示您需要 g_mutex_init
互斥锁:
that has been allocated on the stack, or as part of a larger structure
您不需要 g_mutex_init
互斥:
It is not necessary to initialize a mutex that has been statically allocated
Class 个实例几乎总是不是 静态分配的。
您需要修复构造函数以确保它初始化互斥量 'properly' 例如:
CSomeClass::CSomeClass()
{
g_mutex_init(&G_LOCK_NAME(mSomeCounter));
G_LOCK(mSomeCounter);
mSomeCounter = 0;
G_UNLOCK(mSomeCounter);
}
TBH,我会将互斥量放入 class 持有者中,并将其初始化为其中的一部分,而不是按照您的方式进行初始化,以确保它被初始化、锁定和解锁作为标准 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 初始化确保计数器得到初始化,否则会产生垃圾。