Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Delphi: Общие вопросы > по Mutex: есть вариант, когда не работает |
Автор: Ibragim 13.12.2006, 22:46 | ||
Вечер добрый. Вот надыбал ситуацию, когда Mutex ведет себя не так как хотелось бы. Точнее даже не Mutex, а WaitForSingleObject Вот код
По задумке потоки ждут нажатия кнопки оператором, для того чтобы начать вывод. Однако этого не происходит - выводится все три надписи сразу. В описании функции WaitForSingleObject вычитал (DRKB), что она каким-то образом прекращает ожидание, если поток завершился и при этом даже НЕ освободил Mutex. Кто посоветует, как это обойти? Как сделать, чтобы, несмотря на то что выполнение Execute закончилось, остальные потоки все равно ждали ПРЯМОГО УКАЗАНИЯ что можно выводить (ReleaseMutex(Mutex);)? Заранее спасибо. |
Автор: Alexeis 14.12.2006, 00:44 |
Опять же все обращения к VCL из второго потока можно делать только через Syncronize, все остальные вызовы опасны. |
Автор: bems 14.12.2006, 00:57 |
использовать событие (event) вместо мьютекса |
Автор: Ibragim 14.12.2006, 02:05 | ||
Даже не так. Вот исходник тестовой проги. Единственое обращение к VCL через Syncronize. Эффект тот же. Чего посоветуете?
|
Автор: bems 14.12.2006, 03:26 | ||||
А если с событием тогда 1. создал событие (CreateEvent). 2. создал потоки, вызывающие WaitForSingleObject с хэндлом события 3. по нажатию кнопки (как в примере) вызываешь SetEvent 4. все ждущие потоки выполняются дальше Добавлено @ 03:33
если эта процедура действительно вызывается как обработчик события (читай - из главного VCL потока) то тут ты пытаешся освободить мьютекс которым не владеешь. |
Автор: bems 14.12.2006, 03:53 | ||
вот тут false означает, что у вновь созданного мьютекса нет владельца. Раз так, то один из трех одинаковых потоков (который первым доберется до вызова WaitForSingleObject) моментально его дождется и захватит. Пока он будет рисовать надпись (ну или просто присваивать строку) другие два будут ждать. Когда он выйдет не освободив мьютекса, мьютекс будет щитаться брошенным и его дождется (захватит) слудующий поток
Вобщем нужный эффект будет если ты тутзаменишь false на true. Тогда владельцем свежего мьютекса будет поток который его создал (первичный поток процесса, VCL - поток). По нажатию кнопки он же его освободит, и по очереди(!!!!!!!) начнут просыпаться те три потока (один сделал дело и завершился - проснулся другой) Будет выглядеть как будто они проснулись одновременно, поскольку работают очень не долго. Но более правильно будет тут использовать эвент, а мьютексы оставить для случая когда ни один из этих трех потоков не должен что-то делать одновременно с другими (MUTual EXclusive access - взаимоисключающий доступ) |
Автор: bems 14.12.2006, 04:13 |
и для синхронизации в пределах одного процесса есть более быстрые способы чем объекты ядра. Смотри критические секции и interlocked-функции |
Автор: Ibragim 15.12.2006, 00:55 |
Большое спасибо bems ! Все гуд, разобрался. На всякий случай (для тех у кого возникнет такой же вопрос) напишу как сделал. 1. В одном из потоков TThread (менеджер потоков, ссылку на него и так имели ВСЕ потоки) создал переменную - объект TCriticalSection. 2. Везде, где потокам нужно было для продолжения, завершения работы, показа результатов выполнения и т.д. (у меня около 500 потоков, причем более 20 классов - "видов" потоков) вмешательство оператора - Enter в эту CriticalSection. После - Leave. Работает, даже если Leave вызывается из совершенно другого потока, а тот который сказал Enter давно завершен. Все, тему можно считать закрытой, спасибо всем особенно bems. PS Много предупреждений насчет обращений к визуальным компонентам из-под других потоков. Точно проверено (оч. громоздкие задачи, прямо стресс-тест ![]() 1. Все нормально без всякой синхронизации работает если писать/читать поля TStringGrid, естественно, не одно поле одновременно. 2. Отлично работает TMemo.Add 3. Отлично работает StatusBar |
Автор: bems 15.12.2006, 01:13 | ||
|