У меня вопрос о справедливости критических разделов в Windows, используя методы EnterCriticalSection и LeaveCriticalSection. Документация MSDN указывает: «Нет гарантии о том, что потоки получат право собственности на критический раздел, однако система будет честна для всех потоков». Проблема связана с приложением, которое я написал, которое блокирует некоторые потоки, которые никогда не входят в критический раздел, даже после долгого времени; поэтому я выполнил некоторые тесты с помощью простой программы c, чтобы проверить это поведение, но я заметил странные результаты, когда у вас много потоков, и некоторые моменты ожидания внутри. Это код тестовой программы:Критические разделы Windows критические
CRITICAL_SECTION CriticalSection;
DWORD WINAPI ThreadFunc(void* data) {
int me;
int i,c = 0;;
me = *(int *) data;
printf(" %d started\n",me);
for (i=0; i < 10000; i++) {
EnterCriticalSection(&CriticalSection);
printf(" %d Trying to connect (%d)\n",me,c);
if(i!=3 && i!=4 && i!=5)
Sleep(500);
else
Sleep(10);
LeaveCriticalSection(&CriticalSection);
c++;
Sleep(500);
}
return 0;
}
int main() {
int i;
int a[20];
HANDLE thread[20];
InitializeCriticalSection(&CriticalSection);
for (i=0; i<20; i++) {
a[i] = i;
thread[i] = CreateThread(NULL, 0, ThreadFunc, (LPVOID) &a[i], 0, NULL);
}
}
Результаты этого является то, что некоторые потоки блокируются на протяжении многих циклов, а также некоторые другие ввести критическую секцию очень часто. Я также заметил, что если вы измените более быстрый сон (10 мс), все может вернуться к справедливости, но я не нашел никакой связи между временем сна и честностью. Однако этот тестовый пример работает намного лучше, чем мой реальный код приложения, что намного сложнее и показывает на самом деле голод для некоторых потоков. Чтобы убедиться, что голодные потоки живы и работают, я сделал тест (в своем приложении), в котором я убиваю потоки после ввода 5 раз в критическом разделе: результат состоит в том, что в конце каждый поток входит, поэтому я уверен, что все они живы и заблокированы на мьютексе. Должен ли я предполагать, что Windows действительно НЕ честна с потоками? Знаете ли вы какое-либо решение этой проблемы?
EDIT: тот же код в linux с pthreads работает, как и ожидалось (нет ничьих голодающих).
EDIT2: Я нашел рабочее решение, обеспечивающее справедливость, используя CONDITION_VARIABLE. Это можно сделать из этого сообщения (link) с необходимыми изменениями.
В статье MSDN ничего не говорится о справедливости. Соответственно, с Vista и Server 2003 SP1 их нет. Справедливость вызывает блокировки конвоев, backgrounder [здесь] (http://joeduffyblog.com/2006/12/14/anticonvoy-locks-in-windows-server-2003-sp1-and-windows-vista/). –
Семафоры, критические разделы и мьютексы - не всегда лучший выбор для синхронизации. Для сильно оспариваемых ресурсов вам нужно очень внимательно относиться к тому, что вы используете, иногда позволяя одному потоку управлять этим ресурсом, потому что вам не нужно блокировать какой-либо другой поток на этом ресурсе. Классическим примером может служить пользовательский интерфейс. – Mgetz
@ HansPassant: Я прочитал статью, спасибо, поэтому я должен предположить, что не использовать структуру данных CriticalSection, потому что это несправедливо. Я процитировал эту ссылку: [link] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms683472%28v=vs.85%29.aspx), и он действительно говорит, что я написал , – Mat