Дизайн:
- Синглтон, содержащий ресурс мьютекса
'recursive'
. - 2 потока используют этот синглтон для обновления / управления данными.
- Синглтон - это создается в зависимости от того, какой поток пытается получить к нему доступ первым.
- Создание синглтона имеет глобальную блокировку, чтобы гарантировать, что мы вызываем
mutex attr init
и mutex init
только один раз.
Пример кода: оба потока имеют идентичный поток (только разные данные) и сначала вызывают funcX ()
instance () имеет глобальную блокировку мьютекса () внутри, чтобы гарантировать только 1 создается экземпляр A. Он также имеет дополнительную (! _Instance) проверку вскоре после блокировки, чтобы убедиться, что мы не создадим экземпляр снова.
class A
{
public:
void funcA();
void funcB();
private:
<members>
<boost::recursive_mutex> m;
};
void funcA()
{
m.lock();
<Do something>
m.unlock();
return;
}
void funcB()
{
m.lock()
<Do something>
m.unlock()
return;
}
void funcX()
{
Singleton::instance().funcA();
return;
}
void funcY()
{
Singleton::instance().funcB();
return;
}
========================================================================
A& Singleton::instance()
{
<Global mutex lock>
if (!_instance)
{
createInstance();
}
<Global mutex unlock>
return _instance;
}
Проблема:
Очень редко первый вызов блокировки мьютекса не увеличивает the __count(0)
переменную. Хотя все атрибуты __owner (thread id)
, __nusers (1)
, __lock (2)
обновлены. Всякий раз, когда я пытаюсь зарегистрировать атрибут __kind
, проблема не возникает.
Первоначальные результаты:
Когда возникает проблема, оба потока пытаются инициализировать синглтон (также мьютекс). Из-за глобальной блокировки при создании синглтона только 1 поток продолжает работу, создает мьютекс и инициализирует его типом recursive
. Тогда поток, блокирующий мьютекс, смотрит на устаревшую память и заставляет думать, что тип мьютекса - Нормальный? __kind = 0
. Блокировка мьютекса возвращает успех. И когда вызывается последующая разблокировка, тип мьютекса теперь обновляется как recursive
, и, поскольку pthread
разблокировка не имеет 0 проверок, он в конечном итоге уменьшает __count
до INT_MAX
.
else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex)
== PTHREAD_MUTEX_RECURSIVE_NP, 1))
{
/* Recursive mutex. */
if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
return EPERM;
if (--mutex->__data.__count != 0)
/* We still hold the mutex. */
return 0;
goto normal;
}
Разблокировка также возвращает успех, и мьютекс никогда не освобождается, в результате чего другой поток постоянно находится в состоянии ожидания.
Каковы возможные причины этого сценария? Может ли __kind
как-то испортиться?