Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Синхронизация. Тихая потеря мютекса

16K
22 декабря 2011 года
asmforce
186 / / 05.01.2010
Как показывает трассировка, очерёдность открытия/закрытия мютекса соблюдается верно, работа счётчика функционирует как и задумано, но мютекс rsReadMutex сам собою лочится. При попытке:

[CODE="cpp"]
if( WaitForSingleObject(rsReadMutex, 0) != WAIT_OBJECT_0 )
ReleaseMutex( rsReadMutex );
WaitForSingleObject( rsReadMutex, 0 );
std::cout << GetLastError() << std::endl;
[/CODE]

Вызов GetLastError возвращает ERROR_NOT_OWNER 288, ну оно и понятно. А вот если убрать всю эту эзотерику, оставив только

[CODE="cpp"]
WaitForSingleObject( rsReadMutex, 0 );
std::cout << GetLastError() << std::endl;
[/CODE]

то GetLastError возвращает 0, что какбы говорит: "мютекс занят, мютекс занят не этим потоком, в остальном - всё ок, т.е. сам дескриптор корректный по-прежнему".

Важно заметить, что никаких других аномалий не наблюдается, никто более не использует мютекс. Приведённый код не просто вырван из контекста, а был отдельно написан для тестирования проблемного участка.

Такая вот <эфемизм к контекстуально уместному слову>:

[CODE="cpp"]
HANDLE rsCollaborativeMutex, rsReadMutex;
DWORD rsReaders;


DWORD WINAPI UseRead( LPVOID )
{
for( ; ; )
{
WaitForSingleObject( rsCollaborativeMutex, INFINITE );
std::cout << "ENTER(" << rsReaders << ", " << (rsReaders+1) << ")\n";
if( ++rsReaders == 1 ) {
std::cout << "SEIZE\n";
WaitForSingleObject( rsReadMutex, INFINITE );
}
std::cout << "GOT(" << rsReaders << ")\n";
ReleaseMutex( rsCollaborativeMutex );

Sleep(10);

WaitForSingleObject( rsCollaborativeMutex, INFINITE );
std::cout << "LEAVE(" << rsReaders << ", " << (rsReaders-1) << ")\n";
if( --rsReaders == 0 ) {
std::cout << "RELEASE\n";
ReleaseMutex( rsReadMutex );
}
std::cout << "GOT(" << rsReaders << ")\n";
ReleaseMutex( rsCollaborativeMutex );

Sleep( 100 );
}
return 0;
}


int main( int argc, char **argv )
{
rsReaders = 0;
rsCollaborativeMutex = CreateMutexA( 0, 0, 0 );
rsReadMutex = CreateMutexA( 0, 0, 0 );
rsPrintMutex = CreateMutexA( 0, 0, 0 );

CreateThread( 0, 0, &UseRead, (LPVOID)70000, 0, 0 );
CreateThread( 0, 0, &UseRead, (LPVOID)30000, 0, 0 );

SuspendThread( GetCurrentThread() );
return 0;
}
[/CODE]

А сама смерть выглядит примерно так:
 
Код:
...
LEAVE(1, 0)
RELEASE
GOT(0)
ENTER(0, 1)
SEIZE


Следует заметить, что мютекс может быть несколько (и много) раз успешно пройти цикл открития/закрытия, а сплоховать позже. В очередной раз, закрыв мютекс, мы его уже не откроем.
260
22 декабря 2011 года
Ramon
1.1K / / 16.08.2003
Знакомьтесь, это дед Лок.
Он не любит захват мутекса в одном, а отпускание в другом потоке.

PS: Так же, он не любит забытые volatile, зато их любит оптимизирующий компилятор.
16K
22 декабря 2011 года
asmforce
186 / / 05.01.2010
Я-то вижу, что дедлок, но...
А что там на счёт
Цитата:
Он не любит захват мутекса в одном, а отпускание в другом потоке.

?
Во блин, сам же получил 288. Ходил вокруг да около, но не понял. Видимо спать надо больше. :)
Как заставить полюбить? Можно ли?

Volatile это-то да, но всё это собиралось без оптимизации. Первоначальный код вообще на яз. ассемблера, собирается также без какой-либо оптимизации. Так что это лишнее.

P.S. Да и вообще, volatile не имеет смысла применять к дескриптору, т.к. первый отвечает лишь за запрет "кеширования" значения самой переменной, а не структуры по адресу. А вот к rsReaders в исходном коде помечен у меня volatile, удалил когда форматировал при вставке сюда.

240
22 декабря 2011 года
aks
2.5K / / 14.07.2006
Цитата: asmforce

Как заставить полюбить? Можно ли?


А для чего?

Кстати, зачем вы используете мутекс для межпоточной синхронизации? Виндовый мутекс совсем не одно и и тоже что POSIX мутекс.

16K
22 декабря 2011 года
asmforce
186 / / 05.01.2010
Вообще, странных подход, - для той-же цели приходится создавать двоичный семафор.
Но это всё же лучше чем деадлок :)

Msdn ждёт!
260
22 декабря 2011 года
Ramon
1.1K / / 16.08.2003
Цитата: aks
Кстати, зачем вы используете мутекс для межпоточной синхронизации?


А для чего же его еще использовать?

Цитата: aks
Виндовый мутекс совсем не одно и и тоже что POSIX мутекс.


Практически тоже самое.

POSIX

Цитата:
If the mutex type is PTHREAD_MUTEX_DEFAULT, attempting to recursively lock the mutex results in undefined behavior. Attempting to unlock the mutex if it was not locked by the calling thread results in undefined behavior. Attempting to unlock the mutex if it is not locked results in undefined behavior.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог