TK>А если удариться в специфику то, создает обычно фабрика, а управляет владелец. И в большинстве случаев, это не брат и сестра, а два разных человека.
В случае с фабрикой "тот кто создает" это не фабрика, а код ее вызывающий. Иначе можно ударяться в специфику до утверждения, что объекты создает new или их конструктор.
L>>Не вдаваясь в специфику: обычно рекомендуется чтобы временем жизни объекта управлял тот, кто его создает.
TK>А если удариться в специфику то, создает обычно фабрика, а управляет владелец. И в большинстве случаев, это не брат и сестра, а два разных человека.
Один хрен, ему дали сокетом попользоваться, а он его прибивает.
Создает не фабрика, а тот, кто эту фабрику пинает. Фабрика, в известном смысле, воли не имеет (Вам же не приходит в голову сказать, что объект создает конструктор).
Передавайте коннекшену саму фабрику или на худой конец, "фабричный делегат", если уж всё именно так, как Вы задумали.
Здравствуйте, ylem, Вы писали:
L>>>Не вдаваясь в специфику: обычно рекомендуется чтобы временем жизни объекта управлял тот, кто его создает.
TK>>А если удариться в специфику то, создает обычно фабрика, а управляет владелец. И в большинстве случаев, это не брат и сестра, а два разных человека.
Y>Один хрен, ему дали сокетом попользоваться, а он его прибивает. Y>Создает не фабрика, а тот, кто эту фабрику пинает. Фабрика, в известном смысле, воли не имеет (Вам же не приходит в голову сказать, что объект создает конструктор).
А вот посмотрите на класс StreamWriter in FCL. У него есть такоей конструктор:
public StreamWriter(Stream stream)
и его метод Dispose(Close) закрывает поток, который ему передали в конструкторе.
Такие примеры в FCL еще есть. Например таков internal конструктор класса TcpClient, прнимающий Socket.
И, кстати, внутри TcpListener мы можем видеть примерно такой код:
public TcpClient EndAcceptTcpClient(IAsyncResult asyncResult)
{
// Details skipped.
Socket socket2 = socket.EndAccept(asyncResult);
return new TcpClient(socket2);
}
Как видим, здесь писатели из Microsoft плюнули на возможное OutOfMemoryException и утечку сокета (до сборки мусора). И после этой ветки я склоняюсь к мнению, что правильно сделали .
Y>Передавайте коннекшену саму фабрику или на худой конец, "фабричный делегат", если уж всё именно так, как Вы задумали.
Зачем такие сложности? Какие я получу от этого преимущества в моем коде?
Здравствуйте, jedi, Вы писали:
J>Теперь вопрос. Что будет если случится исключение а) в точке 1; б) в точке 2.
По общепринятым договорённостям, реализация Dispose не должна бросать исключений. То есть внутри реализации Dispose() нужно или вызывать другие Dispose() или гарантировать, что любой код не выбросит исключений. Если теоретически в точке (1) может произойти исключение, то нужно этот код обернуть в try\catch, а после catch вызывать уже _socket.Close(); или что-то ещё.
J>Кто-то должен вызвать Close() сокету (иначе будет висеть у нас занятый порт до сборки мусора).
Теперь второе, более важно замечание. Управлять временем жизни объекта следует тому, что его создал объект. В вашем случае этот принцип нарушен, что может привести к многим неприятностям, например:
J> private void OnAccept(IAsyncResult ar)
J> {
J> using (socket = _listener.EndAccept(ar))
J> {
J> using(var c1 = new Connection(socket)) {
//…
}//using
// …using(var c2 = new Connection(socket)) {
// Использование c2, а сокет уже тю-тю
}//using
J> }
J> }
Если же в своём Dispose объект Connection не будет закрывать сокет, то всё будет хорошо.
Если в вашем случае время жизни сокета 1:1 соответствует времени жизни Connection, и сокет не должен разделяться между разными Connection, то я бы создавал сокет прямо в конструкторе Connection. Если по каким-то причинам это не удобно, то, на худой конец, в Connection надо передавать ещё один флаг — уничтожать сокет или не уничтожать при уничтожении Connection.
J>socket = null;
Это вообще бессмысленный код.
Резюмируя, есть три пути решения (по порядку "удобности" и прочей "хорошести" на мой взгляд) в Connection::Dispose() не закрывать сокет, отдавая эту прерогативу тому, что создал объект
Создавать сокет в конструкторе Connection и гарантированно закрывать в Connection::Dispose(), обрабатывая возможные исключения
Передавать в Connection дополнительный параметр, который скажет, нужно ли закрывать сокет в Connection::Dispose().
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Если в вашем случае время жизни сокета 1:1 соответствует времени жизни Connection, и сокет не должен разделяться между разными Connection, то я бы создавал сокет прямо в конструкторе Connection. Если по каким-то причинам это не удобно, то, на худой конец, в Connection надо передавать ещё один флаг — уничтожать сокет или не уничтожать при уничтожении Connection.
Т.е Вы предлагает в конструктор Connection передавать "IAsyncResult ar" и внутри вызывать "socket = _listener.EndAccept(ar)". Мне почему-то не кажется это хорошим решением.
Хотя бы потому, что классу Connection не нужно знать каким образом было получено соединения — асинхронным BeginAccept, синхронным Accept, или вообще сервер сам присоеденился к клиенту (т.н. passive mode). Кроме того, в более общем случае там будет не Socket, а Stream (например с поддержкой шифрования или без). Так что Ваше решение просто повысит связность кода без всяких бенефитов.
_FR>Резюмируя, есть три пути решения (по порядку "удобности" и прочей "хорошести" на мой взгляд) _FR> _FR>в Connection::Dispose() не закрывать сокет, отдавая эту прерогативу тому, что создал объект _FR>Создавать сокет в конструкторе Connection и гарантированно закрывать в Connection::Dispose(), обрабатывая возможные исключения _FR>Передавать в Connection дополнительный параметр, который скажет, нужно ли закрывать сокет в Connection::Dispose(). _FR>
Да, это все хорошо. За исключение возможного OutOfMemoryException при выполнении "new Connection". Но сам Microsoft на такие ситуации забивает, так что ... (Re[4]: Кошерное использование using
В любом случае спасибо. Но мне кажется Вы немножко догматичны в следовании правилу "Управлять временем жизни объекта следует тому, что его создал объект.". Инога это не работает — например в случае с "обертывающими объектами". См. тот же пример StreamWriter <-> Stream. Кстати, об этом случае хорошо и подробно написано у Рихтера (гл.20, "Интересная проблема с зависимостью").
Здравствуйте, jedi, Вы писали:
_FR>>Если в вашем случае время жизни сокета 1:1 соответствует времени жизни Connection, и сокет не должен разделяться между разными Connection, то я бы создавал сокет прямо в конструкторе Connection. Если по каким-то причинам это не удобно, то, на худой конец, в Connection надо передавать ещё один флаг — уничтожать сокет или не уничтожать при уничтожении Connection.
J>Т.е Вы предлагает в конструктор Connection передавать "IAsyncResult ar" и внутри вызывать "socket = _listener.EndAccept(ar)".
Что бы узнать, как тебе поступить в твоём частном случае нужно сидеть как можно больше кода. По тому, что было показано в сообщении, на которое я ответил, я не могу ничего предложить по
IAsyncResult.
J>Да, это все хорошо. За исключение возможного OutOfMemoryException при выполнении "new Connection". Но сам Microsoft на такие ситуации забивает, так что ... (Re[4]: Кошерное использование using
Не понятно, откуда там утечка.
J>В любом случае спасибо. Но мне кажется Вы немножко догматичны в следовании правилу "Управлять временем жизни объекта следует тому, что его создал объект.". Инога это не работает — например в случае с "обертывающими объектами". См. тот же пример StreamWriter <-> Stream. Кстати, об этом случае хорошо и подробно написано у Рихтера (гл.20, "Интересная проблема с зависимостью").
Если бы ты мог обратить внимание, сколько непонятностей на формах вызывает такое поведение, то понял бы, что повторять эту архитектуру не стоит.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Что бы узнать, как тебе поступить в твоём частном случае нужно сидеть как можно больше кода. По тому, что было показано в сообщении, на которое я ответил, я не могу ничего предложить по _FR>IAsyncResult.
Да я уже давно решил как поступить Сейчас идет "философский" треп. А общий случай был описан в моем исходном сообщении — это передача disposable-объекта в конструктор.
Вы предлагаете радикальное решение — не передавать вообще. Я в свою очередь описал почему все-таки иногда это нужно.
J>>Да, это все хорошо. За исключение возможного OutOfMemoryException при выполнении "new Connection". Но сам Microsoft на такие ситуации забивает, так что ... (Re[4]: Кошерное использование using
public TcpClient EndAcceptTcpClient(IAsyncResult asyncResult)
{
// Details skipped.
Socket socket2 = socket.EndAccept(asyncResult);
return new TcpClient(socket2);
}
Что произойдет если выделение памяти под объект TcpClient завершится неудачей (исключением OutOfMemoryException)?
_FR>Если бы ты мог обратить внимание, сколько непонятностей на формах вызывает такое поведение, то понял бы, что повторять эту архитектуру не стоит.
Кто ж спорит, но иногда-все таки это нужно — если приложение асинхронное. Мы все-таки в реальном мире живем, и следовать умным правилам не всегда получается
J>Что произойдет если выделение памяти под объект TcpClient завершится неудачей (исключением OutOfMemoryException)?
Если случится OutOfMemoryException, то судьба сокета — меньшее, о чем надо будет беспокоиться. Есть основания полагать, что приложение дальше долго не проработает.
Здравствуйте, samius, Вы писали:
J>>Что произойдет если выделение памяти под объект TcpClient завершится неудачей (исключением OutOfMemoryException)? S>Если случится OutOfMemoryException, то судьба сокета — меньшее, о чем надо будет беспокоиться. Есть основания полагать, что приложение дальше долго не проработает.
Если это WinForms приложение — то бог с ним пусть умирает. Если же это корректно написанное серверное приложение, то худшее что должно случиться — нескольким клиентам будет отказано в доступе, остальные продолжат рабту как ни в чем не бывало. Да, администратору будет послано письмо с извещением о том, что случилось и он примет меры — например уменьшит максимум одновременных подключений. Но сервер должен продолжить работу.
Здравствуйте, jedi, Вы писали:
J>Вы предлагаете радикальное решение — не передавать вообще. Я в свою очередь описал почему все-таки иногда это нужно.
Я предложил не "не передовать", а не уничтожать переданный в конструктор объект.
J>>>Да, это все хорошо. За исключение возможного OutOfMemoryException при выполнении "new Connection". Но сам Microsoft на такие ситуации забивает, так что ... (Re[4]: Кошерное использование using
) _FR>>Не понятно, откуда там утечка. J>Что произойдет если выделение памяти под объект TcpClient завершится неудачей (исключением OutOfMemoryException)?
Одно из двух: Приложение завершится, при этом ось закроет сокет
Приложение не завершится, где-то выше по стеку исключение будет поймано и как-то обработано. Тогда при следующей же сборке мусора будет найден объект типа Socket, на который нет ни одной ссылки из корней. Этот объект будет собран GC, у объекта будет вызван файнализатор. У поля объекта m_Handle так же будет вызван завершитель. Никакие ресурсы никуда не утекут.
_FR>>Если бы ты мог обратить внимание, сколько непонятностей на формах вызывает такое поведение, то понял бы, что повторять эту архитектуру не стоит. J>Кто ж спорит, но иногда-все таки это нужно — если приложение асинхронное. Мы все-таки в реальном мире живем, и следовать умным правилам не всегда получается
Не всегда получает придумать, как сделать правильно
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, jedi, Вы писали:
J>Здравствуйте, samius, Вы писали:
J>>>Что произойдет если выделение памяти под объект TcpClient завершится неудачей (исключением OutOfMemoryException)? S>>Если случится OutOfMemoryException, то судьба сокета — меньшее, о чем надо будет беспокоиться. Есть основания полагать, что приложение дальше долго не проработает.
J>Если это WinForms приложение — то бог с ним пусть умирает. Если же это корректно написанное серверное приложение, то худшее что должно случиться — нескольким клиентам будет отказано в доступе, остальные продолжат рабту как ни в чем не бывало.
Я бы сказал, что нескольким будет отказано в доступе, а многим не удастся завершить сессию соединения. Если OOME случился в одном конструкторе, то слишком много шансов на то, что он случится в любом другом конструкторе.
J>Да, администратору будет послано письмо с извещением о том, что случилось и он примет меры — например уменьшит максимум одновременных подключений. Но сервер должен продолжить работу.
Вряд ли это будет полноценная работа.
Здравствуйте, samius, Вы писали:
J>>Да, администратору будет послано письмо с извещением о том, что случилось и он примет меры — например уменьшит максимум одновременных подключений. Но сервер должен продолжить работу. S>Вряд ли это будет полноценная работа.
Я извинюясь, в чемм будет ее неполноценность? Какое-то количество клиентов отвалилось — освободилась память. Она хорошая, никто по ней не ездил, Access Vialotaion не случился, Stack Overflow не было
Здравствуйте, _FRED_, Вы писали:
_FR>Я предложил не "не передовать", а не уничтожать переданный в конструктор объект.
Эмммм... Сокеты — очень ограниченный ресурс. И если их не диспозить совсем, то будет плохо
То же самое — если повиснет открытый файл с блокировкой на чтение/запись — никто с ним не смотжет работать, пока не случится сборка мусора (а случится она может не скоро).
Причем нужна не любая сборка, а первого поколения (ибо у SafeHandle есть финализатор).
J>>>>Да, это все хорошо. За исключение возможного OutOfMemoryException при выполнении "new Connection". Но сам Microsoft на такие ситуации забивает, так что ... (Re[4]: Кошерное использование using
) _FR>>>Не понятно, откуда там утечка. J>>Что произойдет если выделение памяти под объект TcpClient завершится неудачей (исключением OutOfMemoryException)?
_FR>Одно из двух: _FR> _FR>Приложение завершится, при этом ось закроет сокет _FR>Приложение не завершится, где-то выше по стеку исключение будет поймано и как-то обработано. Тогда при следующей же сборке мусора будет найден объект типа Socket, на который нет ни одной ссылки из корней. Этот объект будет собран GC, у объекта будет вызван файнализатор. У поля объекта m_Handle так же будет вызван завершитель. Никакие ресурсы никуда не утекут. _FR>
Почему это плохо, я уже написал выше (и не раз в этом обсужденими). Вы же в очередной раз проводите мне ликбез. Спасибо, я знаком с алгоритмом работы сборщика мусора.
Отступлю от темы.
Не в обиду: хорошо написано.
Если честно, из-за этого явления ничего на рсдн спрашивать больше не хочется. Почему-то все априори считают, что спрашивающий — полный ламер, книжек не читал, пороха не нюхал.
И вместо конструктивного обсуждения — продолжают повторять прописные истины.
. Некто Воронков Василий, с умным видом доказывал мне что доступ к булевой переменной синхронизировать не нужно. При этом не удосужившись ни прочитать код, ни понять что там написано. Но во всех его постах была уверенность, что я о синхронизации впервые слышу и меня нужно непременно просветить. Когда же ему указли на то, что он мягко говоря не прав, человек предпочел замолчать, даже не извинившись передом мной за то, что с умным видом занимался менторством, при этом неся полную чушь.
Здравствуйте, jedi, Вы писали:
J>Здравствуйте, samius, Вы писали:
S>>Вряд ли это будет полноценная работа.
J>Я извинюясь, в чемм будет ее неполноценность? Какое-то количество клиентов отвалилось — освободилась память. Она хорошая, никто по ней не ездил, Access Vialotaion не случился, Stack Overflow не было
Хорошо, несколько клиентов отвалятся, память освободится, вновь подключившемуся клиенту памяти под экземпляр класса Connection хватит. Если никаких других выделений памяти для обработки соединения с клиентом не потребуется, то все будет впорядке. А если нужно десериализовать из сокета какие-то данные, сходить в БД, прочитать граф объектов и т.п., то шансы на успех выполнения итих действий малы.
Здравствуйте, jedi, Вы писали:
_FR>>Я предложил не "не передовать", а не уничтожать переданный в конструктор объект.
J>Эмммм... Сокеты — очень ограниченный ресурс. И если их не диспозить совсем, то будет плохо J>То же самое — если повиснет открытый файл с блокировкой на чтение/запись — никто с ним не смотжет работать, пока не случится сборка мусора (а случится она может не скоро). J>Причем нужна не любая сборка, а первого поколения (ибо у SafeHandle есть финализатор).
Я не предлагал "их не диспозить". Я сказал, что "диспозить" сокет должен тот, что его создал.
J>Почему это плохо, я уже написал выше (и не раз в этом обсужденими). Вы же в очередной раз проводите мне ликбез. Спасибо, я знаком с алгоритмом работы сборщика мусора.
Тогда что ты называешь "утечкой ресурсов"? Ознакомь тогда пожалуйста со своей терминологией
J>Отступлю от темы. J>Не в обиду: хорошо написано. J>Если честно, из-за этого явления ничего на рсдн спрашивать больше не хочется. Почему-то все априори считают, что спрашивающий — полный ламер, книжек не читал, пороха не нюхал. J>И вместо конструктивного обсуждения — продолжают повторять прописные истины.
http://rsdn.ru/Info/Howtoask.xml ты прочитал? Тебе требовалось конкретно описать проблему. Я не вижу где в своём ответе я обратился к тебе как к "ламеру"? Если ты знаешь, что утечки системных ресурсов благодаря сборщику мусора и реализации класса Socket не будет, то объясни как понимать, что "утечка" таки будет? Экстрасенсы у нас сидят все в непрофильных форумах — это там принято "догадываться".
J>Идельный пример — в этой ветке Синхронизация
. Некто Воронков Василий, с умным видом доказывал мне что доступ к булевой переменной синхронизировать не нужно. При этом не удосужившись ни прочитать код, ни понять что там написано. Но во всех его постах была уверенность, что я о синхронизации впервые слышу и меня нужно непременно просветить. Когда же ему указли на то, что он мягко говоря не прав, человек предпочел замолчать, даже не извинившись передом мной за то, что с умным видом занимался менторством, при этом неся полную чушь.
Здравствуйте, samius, Вы писали:
S>Хорошо, несколько клиентов отвалятся, память освободится, вновь подключившемуся клиенту памяти под экземпляр класса Connection хватит. Если никаких других выделений памяти для обработки соединения с клиентом не потребуется, то все будет впорядке. А если нужно десериализовать из сокета какие-то данные, сходить в БД, прочитать граф объектов и т.п., то шансы на успех выполнения итих действий малы.
Т.е. ваше решение — забить, пусть сервер упадет с необрабтанным исключением, данные всех пользователей потеряются, и пусть все клиенты ждут пока администратор проснется и решит проблему?
Здравствуйте, jedi, Вы писали:
J>Здравствуйте, samius, Вы писали:
S>>Хорошо, несколько клиентов отвалятся, память освободится, вновь подключившемуся клиенту памяти под экземпляр класса Connection хватит. Если никаких других выделений памяти для обработки соединения с клиентом не потребуется, то все будет впорядке. А если нужно десериализовать из сокета какие-то данные, сходить в БД, прочитать граф объектов и т.п., то шансы на успех выполнения итих действий малы.
J>Т.е. ваше решение — забить, пусть сервер упадет с необрабтанным исключением, данные всех пользователей потеряются, и пусть все клиенты ждут пока администратор проснется и решит проблему?
Я лишь написал о том, что закрытие единственного сокета после OOME — не суть важная вещь на фоне остальных проблем. В общем случае я не утверждаю, что мне виднее, чем Вам как должен вести себя сервер в такой ситуации. Но толку от того, что Вы не забудете освободить конкретный сокет, будет мало.
Если интересно мнение форумчан на то, что следует предпринимать при OOME, заводите соответствующую тему.
Здравствуйте, _FRED_, Вы писали:
J>>Эмммм... Сокеты — очень ограниченный ресурс. И если их не диспозить совсем, то будет плохо J>>То же самое — если повиснет открытый файл с блокировкой на чтение/запись — никто с ним не смотжет работать, пока не случится сборка мусора (а случится она может не скоро). J>>Причем нужна не любая сборка, а первого поколения (ибо у SafeHandle есть финализатор).
_FR>Я не предлагал "их не диспозить". Я сказал, что "диспозить" сокет должен тот, что его создал.
Вы пробовали написать асинхронное приложение. Если да, то должны знать, что у того кто сокет создал (читай — заакцептил) нет ну ни малейшей информации о том, сколько сокету жить.
J>>Почему это плохо, я уже написал выше (и не раз в этом обсужденими). Вы же в очередной раз проводите мне ликбез. Спасибо, я знаком с алгоритмом работы сборщика мусора.
_FR>Тогда что ты называешь "утечкой ресурсов"? Ознакомь тогда пожалуйста со своей терминологией
Это обозначает, что сокет будет недоступен для использования, заблокированный файл нельзя будет читать другим итп. Да, понятно что когда-нибудь сборщик мусора все почистит.
Но когда это случится — сказать нельзя. Тем более учитывая, что объекты с финализатором в нулевом поколении не чистятся. Вот и все.
Мне странно, что такому уважаемому человеку как Вы, это нужно объяснять
J>>Отступлю от темы. J>>Не в обиду: хорошо написано. J>>Если честно, из-за этого явления ничего на рсдн спрашивать больше не хочется. Почему-то все априори считают, что спрашивающий — полный ламер, книжек не читал, пороха не нюхал. J>>И вместо конструктивного обсуждения — продолжают повторять прописные истины.
_FR>http://rsdn.ru/Info/Howtoask.xml ты прочитал? Тебе требовалось конкретно описать проблему. Я не вижу где в своём ответе я обратился к тебе как к "ламеру"?
Вы мне начали читать лекцию о работе сборщика мусора, видимо предполагая, что я о нем впервые слышу.
_FR>Если ты знаешь, что утечки системных ресурсов благодаря сборщику мусора и реализации класса Socket не будет, то объясни как понимать, что "утечка" таки будет?
Я это объяснил уже раз пять по ходу ветки (втом числе еще раз выше в этом сообщении), я не знаю что еще тут добавить...
_FR>Нет, честно, ты http://rsdn.ru/Info/Howtoask.xml прочитал?
Честно, читал. Я как бы на рсдн не первый год. Но что-либо еще писать с предложением пообсуждать не хочется. Проще с умным видом отвечать в ветках новичков и получать свои плюсы.
Здравствуйте, samius, Вы писали:
S>Я лишь написал о том, что закрытие единственного сокета после OOME — не суть важная вещь на фоне остальных проблем. В общем случае я не утверждаю, что мне виднее, чем Вам как должен вести себя сервер в такой ситуации. Но толку от того, что Вы не забудете освободить конкретный сокет, будет мало.
Ну сокет — это всего лишь пример. Это может быть файл открытый на запись с блокировкой. Или начатая транзакция, которая будет висеть хз сколько итп.
S>Если интересно мнение форумчан на то, что следует предпринимать при OOME, заводите соответствующую тему.
Согласен. Я не совсем корректно поставил вопрос изначально.