![]() |
Модераторы: Partizan, gambit |
![]() ![]() ![]() |
|
Idsa |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2086 Регистрация: 5.12.2006 Где: Томск Репутация: 14 Всего: 62 |
Да, захват, пожалуй, здесь не самое уместное слово... Когда я писал тот пост, мысленно имел в виду AutoResetEvent. Получается мы вызываем Wait, ждем вызова Set, получаем доступ - и тут же AutoResetEvent становится unsignaled. То есть фактически мы захватили AutoResetEvent. Остальные потоки ждут, когда "захвативший" AutoResetEvent поток (который, к слову, находится в другом процессе) его освободит. А он по каким-то причинам его не освободил и завершился (например, рубанули его через TaskManager). Mutex в этом случае сгенерирует AbandonedMutexException... а как быть с EventWaitHandle?
По-моему это всего лишь частный случай DeadLock'а. Как я понимаю, DeadLock'ом можно назвать любую "мертвую" блокировку. А в описанной мной ситуации возникает именно "мертвая" блокировка, потому что потоки ждут сигнала от потока, который уже завершился. Это сообщение отредактировал(а) Idsa - 3.4.2009, 15:51 |
||||
|
|||||
PashaPash |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
А в случае WaitHandle использовать Manual Reset Event - он как раз и предназначен для сценария - один дал сигнал - все получили. Нет, дедлок это именно взаимная блокировка: 1. Несколько живых процессов 2. Каждый процесс держит ресурс, который необходим другому для продолжения. А "метрвая" она потому, что после появления не может быть устранена без убийства одного из процессов. А в описанной тобой ситуации просто нехватка ресурса под названием "разрешение ровно одному из слушателей на продолжение работы". И создана она именно ограничением "ровно одному" == AutoResetEvent. Запусти управляющий процесс еще раз - получишь вполне легальное завершение работы. |
|||
|
||||
Idsa |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2086 Регистрация: 5.12.2006 Где: Томск Репутация: 14 Всего: 62 |
Честно говоря, не понял, чем здесь поможет ManualResetEvent. Ведь так же все будут ждать команды Set от потока, который уже завершился.
Не факт. Его может озадачить то, что EventWaitHandle "закрыт", и он может подвиснуть (если, конечно, не реализована разруливающая такую ситуацию логика). К тому же, кто сказал, что у нас единый управляющий процесс? Мы же рассматриваем общий случай, не так ли? ![]() Да и вообще, тогда и в случае классического deadlock'а с двумя Mutex'ами можно сказать что-нибудь вроде "запусти потоки еще раз - авось deadlock'а не случится". Почему "ровно одному"? Как я писал выше, если бы Set'а ждало множество потоков, ничего бы не изменилось. Я не настаиваю на том, что эта ситуация должна называться deadlock'ом, но , на мой взгляд, здесь ни при чем. |
||||
|
|||||
PashaPash |
|
||||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
При ManualResetEvent событие получают сразу все ждущие потоки. (All waiting threads are released). Что значит "подвиснуть"? Насколько я понял, в задаче каждый управляемый процесс ждет события в background-потоке, и при получении - инвокает в главном что-то типа File.Exit. И что значит EventWaitHandle закрыт? Он или signaled, или non-signaled. Что занчит озадачить? Системное событие создается управляемым потоком при старте, и если уже signaled - сбрасывается. А управляющему вообще все равно какое там состояние, он только умеет set вызывать ![]()
Как это ничего? все бы одновременно дождались события, и вышли. Неплохой эффект от "ничего" ![]() Добавлено через 35 секунд Idsa, набросай схему на Mutex-ах, интересно как ты себе это представляешь ![]() |
||||
|
|||||
Idsa |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2086 Регистрация: 5.12.2006 Где: Томск Репутация: 14 Всего: 62 |
Ок. Сегодня вряд ли успею... так что, по всей видимости, флейм переносится на завтра ![]() ![]() |
|||
|
||||
archeg |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 612 Регистрация: 6.1.2007 Где: Киев Репутация: 11 Всего: 27 |
Блин, народ) не гоните
![]() Вы реально будете для такой фигни юзать элементы ядра винды? Во втором приложении, которое должно освободить ресурсы при выходе пишем:
В первом приложении, которое убивает второе, пишем:
Вместо "WindowsFormsApp" прописываем имя процесса второго приложения. Вместо [0] можно перебрать список и найти то которое нужно (как-то) или убить все например. И - ![]() -------------------- ИМХО задница есть универсальный интерфейс. Ибо через задницу можно сделать абсолютно ВСЕ (bash.org.ru) Дядька всегда можно спросить в аське, если не задалбывать - не откажет ![]() И вообще, на самом деле я студент, и ненавижу обращение на "Вы") Тут все свои ;) |
||||
|
|||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
Настоящие джедаи так не делают ![]() -------------------- СУВ, Partizan. |
|||
|
||||
Idsa |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2086 Регистрация: 5.12.2006 Где: Томск Репутация: 14 Всего: 62 |
||||
|
||||
PashaPash |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
archeg, а если закрываемое приложение будет показывать модальный диалог? Или при закрытии спросит "точно выйти"? Может сразу перейти к taskkill?
|
|||
|
||||
Idsa |
|
||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2086 Регистрация: 5.12.2006 Где: Томск Репутация: 14 Всего: 62 |
Продолжаем разговор.
Для тех, кто в порыве страсти флейма забыл задание, напоминаю, какую задачу мы решаем:
PashaPash вполне резонно предложил использовать EventWaitHandle. Однако возник вопрос уведомления клиента о том, что сервер помер. Я написал простенькое приложение, которое эмулирует данную задачу при помощи Mutex, Semaphore (зачем понадобился Semaphore расскажу далее) и EventWaitHandle. Код сервера:
Код клиента:
В приведенном коде используется Mutex. Для того чтобы протестировать другие подходы, нужно раскомментировать соответствующие строчки (ну а строчки с Mutex - закомментировать). Запускаем сервер (можно не из Студии). Он создает определенный объект синхронизации (причем создает его в "занятом" состоянии) и ждет 10 секунд, прежде чем освободить ресурс. В это время мы запускаем клиент (желательно из Студии, чтобы посмотреть, что за Exception валится). Далее есть 2 варианта: 1. Подождать, пока пройдет 10 секунд, сервер освободит ресурс (и в скором времени завершится), а клиент закончит Wait и радостно завершится. 2. Открыть окошко сервера и нажать Ctrl+C, тем самым вырубив сервер, - и посмотреть на реакцию клиента. С первом вариантом справляются на отлично и Mutex, и Semaphore, и EventWaitHandle. А вот на втором варианте остановимся подробнее. При использовании мьютекса сразу после нажатия Ctrl+C на клиенте вывалится AbandonedMutexException с Message'м "Ожидание закончилось вследствие освобождения семафора.". Этот чертов локализованный Framework... Я надеюсь на то, что это ляп переводчиков, и в оригинальном фреймворке в Message говорите об освобождении mutex'а, а не semaphor'а. На первый взгляд, может показаться, что это несущественно, ведь, в конце концов, мьютекс - одноместный семафор. Однако, в .NET есть отдельный класс Semaphor, который ведет себя совершенно по-другому. Проведя аналогичный эксперимент с Semaphor'ом, я увидел печальную картину: сервер убивается, а клиент, как ни в чем не бывало, продолжает ждать, ждать, ждать... EventWaitHadnle ведет себя точно так же, как и Semaphor. В попытках понять такое поведение, я провел еще несколько экспериментов, которые открыли мне ряд интересных закономерностей. Сами закономерности я описывать не буду, сформулирую лишь получившуюся в результате логическую цепочку. Первый важный момент - для мьютекса, несмотря на его кросспроцессность, действует ограничение: в каком потоке мы его захватили, в этом же должны и освободить. Таким образом, если поток, который ранее захватил мьютекс (причем в не зависимости от того, создавал ли он мьютекс), завершается, освободить мьютекс уже никак не получится. Поэтому для всех Wait'ов (как текущих, так и будущих) во избежание deadlock'а (PashaPash, ну а как еще назвать эту ситуацию? имхо, deadlock чистой воды) генерируется Exception. Таким образом, работа Mutex'а полностью определяется постулатом о невозможности его освобождения не из того потока, который его захватил. Зачем нужно такое ограничение? Думаю, разработчики Windows (ведь Mutex - объект ядра) сделали все правильно: раз Mutex служит для ограничения доступа к одному объекту, то освобождать его должен именно тот, кто захватил (а те, кого такое поведение не устраивает, всегда могут воспользоваться одноместным семафором). Ни на Semaphore, ни на EventWaitHandle такое ограничение не действует, поэтому при завершении потока, который (пусть даже единолично, как в случае одноместного Semaphore или AutoEventReset) захватил ресурс, исключение не генерируется: мы всегда можем освободить Semaphore или EventWaitHandle из любого другого потока. Однако, насколько я понимаю, этот нюанс делает Semaphor и EventWaitHandle непригодными для полноценного решения поставленной задачи. И если Semaphor сюда был притянут за уши (просто интересно стало...), то насчет EventWaitHandle действительно жаль: очень элегантное, казалось бы, решение. P. S. PashaPash, я так и не понял, какие преимущества при решении данной задачи у ManualResetEvent по сравнению с AutoResetEvent... PP. S. Обладатели нелокализованного Framework'а, скажите, как у вас формулируется Message для AbandonedMutexException? PPP. S. PashaPash, я в этой обращался к тебе. Уж не знаю, проглядел ты или проигнорировал... но мне очень интересно твое мнение на сей счет ![]() PPPP. S. Прошу помощи в решении следующего вопроса: http://forum.vingrad.ru/forum/topic-254143.html |
||||||
|
|||||||
PashaPash |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
Idsa Что-то тебя пробило... Дело в том, что точного определения задачи не дано
![]() 1. Не ясно, блокируется ли второе приложение до получения события. Если блокируется - то вызвана ли необходимость блокировки захватом общего ресурса со стороны сервера? Да - mutex/semaphore. Нет - Event. Если не блокируется, 2. Не ясно, сколько может быть "вторых приложений". Если два и более - то какие из них должны получить уведомление? Один (AutoResetEvent/Mutex), Все (ManualResetEvent), N(Semaphore)? 3. С терминологией тоже непонятки - у меня с клиентом ассоциируется отправляющий сообщение... Почему ты решил, что никак не отреагировавший на смерть сервера клиент - это неправильное решение задачи? В оригинале - клиент - win приложение, которое как раз должно спокойно работать, если от сервера ничего не пришло. И даже если сервер на был запущен. Термин "захватил" применим только к Mutex-у. EventWaitHandle не "захватывается", и не служит для захвата ресурса. Он просто "существует" в одном из двух состояний. Представь себе систему со школьным звонком. Каждый может подойти и включить/выключить звонок. Каждый знает состояние звонка в текущий момент. Один человек (клиент) решает подождать звонка - сидит и ждет смены состояния на "звенит", может быть читая книжку вторым потоком. Кто-то (сервер) вклчает звонок. Клиент тут же получает уведомление и уходит, вызвав какой-нибудь Close(). Ни один из них не захватывает звонок - это просто физически невозможно. Сервер может подойти, посмотреть на звонок (new EventWaitHandle, OpenExisting), и уйти. Сервер может вообще умереть еще вчера. Сервера может даже не существовать. До вызова Set/Unset сервер на звонок только смотрит на висящий на стене звонок, а не хватает его, не прячет в сумку, не ложит в личный сейф... Поведение клиента не зависит от сервера. Оно зависит только от звонка. Он может не дождаться звонка (прождав какой-то таймаут, который сам определяет). Может зайти директор и отправить клиента домой до звонка (пользователь закроет клиента, не важно, через ui или убив). Но как-то странно утверждать, что если ответственный за включение звонка не придет - то учеников обязательно придется расстрелять, т.к. "дедлок" - придется выбрать жертву ![]() |
|||
|
||||
Idsa |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2086 Регистрация: 5.12.2006 Где: Томск Репутация: 14 Всего: 62 |
Это если мы говорим о настоящих событиях. В случае же EventWaitHandle, нам все равно где-то придется вызвать Wait - и тогда приложение в случае конфуза сервера уже не сможет нормально работать. Судя по всему, нужно просто предусмотреть возможность сбоя - и вынести ожидание в отдельный поток. Насколько я понял твой пример, ты изначально и имел в виду такой подход... А как тогда говорить про EventWaitHandle? "Перевел объект в состояние unset"? Нелаконично как-то... |
|||
|
||||
PashaPash |
|
||||||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
Это вполне настоящее событие, просто это не event в терминах .net. В примере выше звонок - это настоящее событие? Но ведь его получают вообще все, а не только какие-то подписавшиеся. А реагируют только ждущие.
Скорее установил/сбросил - кривизна перевода. Set - самое многозначное слово в английском, 200+ значений ![]() Кстати, лучше переписать код вот так, тогда порядок запуска будет не важен:
|
||||||
|
|||||||
Idsa |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2086 Регистрация: 5.12.2006 Где: Томск Репутация: 14 Всего: 62 |
А как это его все получают? (я говорю про практическую реализацию, а не про дребезжание звонка ![]() Мне кажется, из логики твоего повествования выбивается AutoResetEvent. Или можно сделать снисхождение, посчитав его частным случаем? ![]() Договорились ![]() А, кстати, про семафоры как говорить? Ведь захватил не подходит, потому что семафор может быть многоместный. Может, "захватил одну десятую часть семафора"? ![]()
Первый - сервер, второй - клиент? Не понял глубины мысли... Это сообщение отредактировал(а) Idsa - 4.4.2009, 17:01 |
||||
|
|||||
PashaPash |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
Получают - не совсем правильно, скорее, видят и могут начать ждать. Нет подписавшихся. Подписка подразумевает механизм Publish/Subscribe - а в случае Event-ов у тебя никто событие не публикует - оно существует само по себе. Есть только ожидающие установки события.
Ага, абстракция дырявая. В любом порядке, любое количество обоих видов. ![]() |
|||
|
||||
![]() ![]() ![]() |
Прежде чем создать тему, посмотрите сюда: | |
|
Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов. Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :) Так же не забывайте отмечать свой вопрос решенным, если он таковым является :) Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |