【问题标题】:G_LOCK behavior changed from glib 2.46 to glib 2.48?G_LOCK 行为从 glib 2.46 更改为 glib 2.48?
【发布时间】:2016-04-18 08:01:45
【问题描述】:

我正在查看一段代码,该代码直到最近才有效。基本上,我有一个 C++ 类,我在其中使用 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 的相关信息,但找不到任何东西。当使用 G_LOCK 宏和最近的 glib 版本时,有没有其他人注意到有趣的效果?我错过了这里的一些变化吗?

【问题讨论】:

    标签: c++ multithreading glib ubuntu-16.04


    【解决方案1】:

    首先,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 初始化确保计数器被初始化,否则会产生垃圾。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多