Я не могу опубликовать исходный код, но могу объяснить его части на концептуальном уровне и надеюсь, что мне помогут понять, почему мое решение работает.
У меня есть приложение, которое имеет 3 потока: A, B и C (основной поток).
Поток B содержит список объектов Foo.
Каждый объект Foo содержит ровно 1 объект Mutex, который является оберткой над рекурсивными мьютексами, и набор методов, используемых для синхронизации и установки различных атрибутов, с использованием Mutex, и 2 метода используются для установки и получения атрибута markForDelete ,
Все, что делает поток B, это итерация по указанному списку с использованием итераторов и удаление объектов Foo, помеченных для удаления, или выполнение других инструкций в противном случае. Это единственный поток, отвечающий за уничтожение объектов Foo с использованием основного кода, подобного следующему:
while (running)
{
fooListLock->Lock();
for (vector<Foo*>::iterator it = fooList.begin(); it)
{
if (it->isMarkedForDelete())
{
it = fooList.erase(it);
}
else
{
it->execute();
}
}
fooListLock->Unlock();
sleep (sleepVariable);
}
Поток A и C создадут и добавят объекты Foo в список, и они также могут пометить их для удаления, и это будет сделано синхронизированным образом с использованием других мьютексов.
Поток C иногда будет закрыт и всегда после этого будет перезапущен, но контролируемым образом и никогда во время выделения / освобождения памяти и всегда будет освобождать заблокированные мьютексы.
Проблема в том, что когда Moox Foo выделяется в куче памяти (через new
оператор) приложение перейдет в состояние тупика, когда поток C хочет получить доступ к ресурсам, заблокированным потоком A, а первый хочет получить доступ к ресурсу, заблокированному потоком B, а поток B заблокирован мьютексом Foo, который заблокирован, но не имеет владельца. Используя GDB, я обнаружил, что значение владельца pthread_mutex_t в Mutex равно 0 или отрицательному числу, не соответствующему id каких-либо потоков. Конец тупика блокировки происходит в этом фрагменте кода в потоке B: if (it->isMarkedForDelete())
,
Мое интуитивно понятное решение — разместить Mutex от Foo в стеке, и он работает без каких-либо других модификаций! Таким образом, приложение никогда не заходит в тупик.
Компиляция выполняется с использованием g ++ 4.8 с установленным флагом O2.
Я знаю, что это не так много, но может кто-нибудь помочь мне понять, почему мое решение работает?
Я, конечно, верю, это не имеет ничего общего с кучей ошибок. Скорее всего, вы неправильно инициализируете мьютекс. Вы звоните pthread_mutex_initialize?