2016-04-18 10 views
2

Я ищу фрагмент кода, который работал до недавнего времени. В принципе, у меня есть класс C++, в котором я защищаю переменную с помощью макроса G_LOCK_DEFINE.Поведение G_LOCK изменилось с glib 2.46 до glib 2.48?

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, которая подтолкнула мою glib-версию к 2.48.0-1ubuntu4. Я уже проверил журнал изменений для соответствующей информации о G_LOCK, но ничего не смог найти. Кто-нибудь еще заметил забавные эффекты при использовании макросов G_LOCK с недавней glib-версией? Я пропустил некоторые изменения здесь?

ответ

4

Во-первых, все, что 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); 
} 

ТВН, я бы поставил семафор в держатель класса, и инициализировать его как часть этого, а не так, как вы делаете это, чтобы убедиться, что он будет инициализирован, заблокирован и разблокирован, как часть стандартной семантики C++ RAII.

Если вы используете небольшой основной корешок, что-то вроде:

main() { 
    { CSomeClass class1; } 
    { CSomeClass class2; } 
    { CSomeClass class3; } 
} 

и ваш код, есть хороший шанс, что он будет висеть в любом случае. (Мой макинтош разбился пример с:. 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 гарантирует, что счетчик инициализируется, в противном случае она будет иметь мусор