4

Только зацикливанием main можно решить данную задачу или есть более красивое решение?

Pavel Mayorov
  • 58,537
iluxa1810
  • 24,899
  • 2
    Быть может имеет смысл подумать в сторону сервисов? – Aleksandr Zharinov Jun 21 '16 at 06:26
  • 2
    На какие именно события? –  Jun 21 '16 at 06:29
  • @PashaPash, подключение/отключение внешних дисков. – iluxa1810 Jun 21 '16 at 06:36
  • Для таких целей лучше все таки сервис, вот и статья на тему того как https://habrahabr.ru/post/102826/ – rdorn Jun 21 '16 at 07:33
  • Лень писать ответ - поэтому набросаю сюда ключевых слов. "RegisterDeviceNotification, WM_DEVICECHANGE, невидимая форма, Application.Run()". – Pavel Mayorov Jun 21 '16 at 07:38
  • @PavelMayorov ну кстати, да, можно еще в трей форму свернуть, что-то я не подумал сразу =) – rdorn Jun 21 '16 at 08:11
  • @rdorn, еще, можно очень просто и быстро делать сервисы с помощью TopShelf. – Andrey K. Jun 21 '16 at 12:09
  • @rdorn, в чем преимущество TopShelf ? – iluxa1810 Jun 21 '16 at 13:45
  • Это скорее к @AndreyK. вопрос, но по я так понимаю, что преимущество в том, что часть работы уже сделана, остается только прикрутить нужные декорации и специфический функционал. – rdorn Jun 21 '16 at 13:48
  • @iluxa1810, без TopShelf - геморрой, а с TopShelf - 3 строчки. Отлаживать просто. Делаешь как консольное приложение, потом передаешь параметр (в запуске из командной строки), и оно запускается как служба. Это не альтернатива винсервису, а тот же винсервис. Наизусть не помню, как именно пользоваться, но примерно так. Короче, это супер штука, когда нужно сделать винсервис. – Andrey K. Jun 21 '16 at 15:39

3 Answers3

7

Суть приложения — это выполнение функции Main, пока это приложение должно работать. Соответственно, если приложение должно работать вечно, то не выходить из метода Main — это единственное верное и абсолютно естественное решение.

Пусть вас не обманывают разные платформы вроде Windows.Forms — в конечном счёте ваш код уходит корнем в метод Main в .NET, который уходит корнем во входной адрес в заголовке исполняемого файла. Когда функция завершает выполнение, ось считает процесс выполнившимся.

С точки зрения реализации, конечно, не надо делать while (true) Thread.Sleep(1), вместо это следует по-нормальному дожидаться событий, на которые приложение должно реагировать. Например, если приложение должно реагировать на ввод в консоль, то в цикле можно сделать чтение Console.ReadLine() — эта функция остановит выполнение без пожирания процессорного времени и вернёт строку тогда, когда она есть.

Правда в винде "вечно работающие приложения" обычно делают службами. Служба регистрируется в системном списке служб, получает средства для управления выполнения пользователем, ось следит за запуском и работой службы и т. п. Консоль удобна разве что для отладки, потому что можно выводить журнал сразу в консоль для наглядности. Если приложение должно тесно взаимодействовать с пользователем, ещё можно сделать иконку в области уведомлений.

Kyubey
  • 32,103
1

Консольное приложение не может работать в ФОНЕ. Консоль - это stdin, stdout и stderr. ЛЮБОЕ приложение работающее в фоне обязано отключить эти стандартные файлы.

Такое приложение, в linux терминологии, называется "демоном". На виндовозном языке - "сервис".

Существуют строгие правила написания демонов. Например, как они должны отключаться от консоли. Эти правила изложены во многих местах. Например здесь:

http://citforum.ru/programming/unix/daemons/

Любой демон находится в состоянии ожидания, до тех пор, пока не происходит некоторое событие. Ну, например:

  • Демон получил сигнал SIGHUP
  • Демон получил извещение от inotify
  • Пришло сообщение из канала или очереди сообщений ...
  • В вопросе спрашивается, очевидно, о Windows, а вы в вашем ответе рассказываете о программировании юниксовских daemon'ов. – VladD Jun 21 '16 at 09:13
  • @VladD, из вопроса не вытекает платформа. – ixSci Jun 21 '16 at 09:40
  • @ixSci: Не, ну формально конечно не вытекает. Но в реальной жизни что-то я не видел среди юниксоидов радостного хайпа по поводу C#, так что в ответе не хватает фразы «В том невероятном случае, если ваша целевая платформа — Linux, ...». – VladD Jun 21 '16 at 09:52
  • по поводу C# Перечитал вопрос ещё раз, но не увидел там слов "C#" или "Windows". Может не туда смотрю?

    Писать демона на C# - это круто! :-) Можно, наверное, на РНР попробовать... Может, всё-таки, шурупы - закручивать, а гвозди - забивать ?

    – Сергей Jun 21 '16 at 10:13
  • @Сергей, смотрите какие теги у вопроса(голубые прямоугольники в вопросе) – ixSci Jun 21 '16 at 11:17
  • Или я смотрю не туда, или мы вообще о разном говорим! :-(

    Я вижу в заголовке:

    "Как сделать консольное приложение, которое бесконечно работает в фоне и реагирует на события?"

    О каких голубых прямоугольниках вы говорите? Можно скриншот глянуть, как это у Вас выглядит ?

    – Сергей Jun 22 '16 at 04:45
  • А!!!! Увидел, наконец! Ладно, Вы правы - вопрос действительно по C#... – Сергей Jun 22 '16 at 04:47
1

Во-первых работающее в фоне приложение конечно должно быть сервисом (Windows Service). Но полезно реализовать двоякий режим -- чтобы можно было также запустить с командной строки -- нужно для проверок и отладки.

Во-вторых, нужен шедулер (scheduler) -- часть программы которая отвечает за вызов задач (tasks, jobs) по расписанию или по внешним событиям. Шедулер лучше взять готовый (например, Quartz.net) -- чтобы не наступать снова на все те же самые грабли.

nzeemin
  • 1,868