CreateMutex с bInitialOwner = true кажется странным - PullRequest
1 голос
/ 13 февраля 2012

Я действительно в недоумении.Я внимательно прочитал статьи MSDN, но до сих пор не могу понять, что происходит.Моя проблема заключается в следующем: при запуске нескольких процессов со следующим кодом все работает:

HANDLE m = CreateMutex(NULL, FALSE, L"MyMutex");
char c[20] = "2print";
for(int iter = 0; iter<100; ++iter) {
    WaitForSingleObject(m,INFINITE);
    for(int i=0;i<(int)strlen(c);++i) {
           for(int j=0;j<10000;++j)
                 printf("%c",c[i]);
    }
    BOOL ok = ReleaseMutex(m);
}
CloseHandle(m);

, то есть разные процессы печатают каждый свой ход и освобождают мьютекс, пока не завершится вся печать.

НО изменение CreateMutex на: (bInitialOwner с FALSE на TRUE)

HANDLE m = CreateMutex(NULL, TRUE, L"MyMutex");

первый создатель не освободит мьютекс!другие процессы просто сидят там.Что меня поразило, так это то, что, добавив еще один releaseMutex, он меняется:

BOOL ok = ReleaseMutex(m);

на:

BOOL ok = ReleaseMutex(m);
ok = ReleaseMutex(m);

заставить его работать!

я действительно запуталсяПочему первый создатель не выпустит мьютекс правильно?я попытался распечатать все ошибки, используя GetLastError, и то, что я получил, кажется разумным, например, ERROR_ALREADY_EXISTS для создателей, следующих за первым, что я и ожидаю (MSDN говорит, что в этой ситуации bInitialOwner просто игнорируется).

1 Ответ

4 голосов
/ 13 февраля 2012

Когда вы используете bInitialOwner=TRUE, создатель мьютекса автоматически получает мьютекс.Затем, когда вы вызываете WaitForSingleObject, он снова получает мьютекс .Поскольку мьютексы win32 являются рекурсивными мьютексами, вы должны освобождать один раз для каждого полученного мьютекса - поэтому для первоначального создателя требуется два вызова ReleaseMutex (однако каждый другой поток должен освобождать только один раз!)

Избегайте этого, либо не используя bInitialOwner, либо пропуская WaitForSingleObject в первом цикле только , если есть, только если GetLastError() != ERROR_ALREADY_EXISTS.Вам нужно будет позвонить SetLastError(0) до CreateMutex, чтобы очистить код ошибки, если вы выберете последний вариант.

Если вам нужен bInitialOwner только для какой-либо начальной настройки, это упростит ваш код, еслиВы сбрасываете мьютекс до входа в общий цикл.В противном случае я настоятельно рекомендую просто не использовать bInitialOwner, если только у вас нет веских причин для этого.

...