LINUX.ORG.RU

Архитектура C для чайников


0

3

Здравствуйте.

Прошу людей, близких к миру C, посоветовать, поправить мои (скудные) представления о том, как должна выглядеть модульная система на C.

Пусть это будет кофеварка и лампа, управляемые через браузер. Кофеварка подключена к компьютеру через COM-порт. А лампа - через TCP. И есть, собственно, пользователь, отдающий команды через браузер по websockets.

Итого имеем как минимум 4 процесса - драйвер кофеварки, драйвер лампы, обработчик websockets-подключения. И основной процесс, координирующий действия первых трех. Назовем его Менеджер.

Я представляю себе это таким образом: менеджер - исполняемый файл. А три других модуля - динамические библиотеки. Менеджер загружает модули и вызывает в них некую функцию «start», которая форкает модуль и он приступает к управлению устройством.

И здесь у меня вопрос: насколько приемлимо использовать libuv в Менеджере? Я читал, что всё, что связано с процесами - чрезвычайно непереносимо. И что мультизадачность очень сложна и лучше ее всячески избегать.

Как обмениваться информацией между процессами? Можно ли обойтись трубами или придется использовать какой-нибудь nanomsg/0mq?

Можно ли передавать между процессами структуры прямо из памяти или придется сериализовать/десериализовать? Как вообще обычно передают сообщения между процессами?

Или всё тут написаное полная хрень и лучше делать по-другому?

★★★★★

Традиционно в случаях ожидания ио на файлах, портах и сокетах используют select, epoll и подобные штуки. Впрочем там тоже не всё гладко с переносимостью.

PolarFox ★★★★★
()
Ответ на: комментарий от PolarFox

С файлами и сокетами понятно. А между процессами? Скажем, когда кофеварка хочет сообщить менеджеру что кофе готово. И в то же время менеджер должен иметь возможность отправлять кофеварке команды. Получается, процессы должны слушать друг друга в обе стороны. Или может всё намного проще?

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Очередь сообщений нужна тебе. В boost::ipc есть из коробки, но это кресты. На сишечке тоже можно запилить или найти готовую.

В общем случае решается так - придумываешь простенький rpc протокол, а дальше гоняешь его через любой канал данных, начиная от сокетов, заканчивая файлами, в том числе, через потоки ввода вывода. Вообщем там где тебе удобней.

pon4ik ★★★★★
()
Ответ на: комментарий от makoven

Максимально переносимое решение в таком случае, имхо — несколько различных процессов (исполняемых файлов), связанных друг с другом по tcp, желательно по простому текстовому протоколу аля http (а может и по самому http). Дополнительный бонус — получаем возможность исполнения на нескольких раздельных машинах.

PolarFox ★★★★★
()

Или всё тут написаное полная хрень и лучше делать по-другому?

Достаточно одного процесса в цикле, ожидающего сигналов от лампы, кофеварки и пользователя.

Раздельные процессы нужны только в определенных случаях, если на то есть веские причины.

Deleted
()
Ответ на: комментарий от pon4ik

Да мне не нужно через любой канал. Делают же как-то люди подключаемые модули. Врятли каждый городит rpc

makoven ★★★★★
() автор топика
Ответ на: комментарий от Deleted

А как это реализовать в одном процессе? Хочется чтобы каждый модуль был независимой сущностью. Если, например, понадобится запустить ту же програму без одного модуля. Или добавить парочку новых. Чтобы при этом не требовалось переписывать Менеджер - добавлять в него специфичные для конкретного модуля вещи.

makoven ★★★★★
() автор топика
Ответ на: комментарий от PolarFox

Намучался я с парсингом текстовых протоколов) Теперь C API кажется более разумным вариантом

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от makoven

Посмотрите, как реализованы http-серверы, например. Ключевой момент - вызовы вроде select() и epoll(). Однопоточная архитектура отнюдь не исключает использования модулей.

Делить на отдельные процессы не стОит, если нет к этому явных предпосылок - требование повышенной взломоустойчивости, ограниченное адресное пространство, принципиальная возможность работы по одиночке и т.д. В большинстве случаев, хватает однопоточного или многопоточного приложения и какого-либо epoll().

Deleted
()
Ответ на: комментарий от Deleted

Ок. Идеей проникся. Значительно проще моих умозаключений.

Еще вопрос. Один процесс слушает сокеты/файлы, реагирует на действия. Одно из действий (скажем, вызов внешнего lua-скрипта) затягивается на пару сотен милисекунд - epoll встает колом и данные теряются?

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Одно из действий (скажем, вызов внешнего lua-скрипта) затягивается на пару сотен милисекунд

В вашем цикле не должно быть вообще ничего блокирующего, кроме epoll(). Если надо выполнить долгий скрипт, выносите это в отдельный поток. Скомандуйте ему начать выполнение, и ждите от него сигнала о завершении операции.

Deleted
()
Ответ на: комментарий от Deleted

А если основной поток вызовет пару таких скриптов, а скрипты используют общие ресурсы/переменные..

В общем, попробую для начала одним потоком. Не получится - буду городить mq/ipc/rpc.

Спасибо за пояснения)

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Да не, это такой местный, обожравшийся грибов и скуривший дедушкины носки, пасанчик, у которого кал изо рта льется. Особо начинает исходить на Г, когда кто-то говорит волшебные заклинания, например «сишечка устарела», «кресты рулят», «руст заменит сишечку». Местные анонимусы очень любят его и иногда играют в игру «кто опустит царя быстрее». Правда его что-то давно не видно :( не случилось ли чего.

anonymous
()

Что-то ты фигню какую-то напридумывал. Запускаешь 1 демон, который будет слушать вебсокет на определенном порту-адресе, обрабатывать команды и направлять нужное в порт. Чтобы потоки этого демона между собой могли общаться, можно либо глобальную самопальную очередь использовать, либо действительно какие-нибудь очереди сообщений.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от makoven

кофе готово

убивать

по топ-посту. асинхронность может понадобиться если нужна производительность, но для этого нужно немного повернуть себе моск. лучше упакуй в один процесс.

anonymous
()
Ответ на: кофе готово от anonymous

Как без асинхронности упаковать в один процесс, если в задаче присутствуют io-блокировки?

makoven ★★★★★
() автор топика
Ответ на: комментарий от Eddy_Em

Правильно я понял твою мысль?:

  • драйвера кофеварки и лампы запускаем в виде тредов основного процесса.
  • Каждый тред поллит свое устройство.
  • Есть некая глобальная очередь (переменная), в которую каждый тред и основной процесс пушат (и забирают из нее) сообщения. И поскольку мы находимся в рамках одного процесса, нам не потребуется ipc - можно тупо добавлять структуры в очередь.
makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 2)
Ответ на: комментарий от anonymous

Ну как же не случилось? Случилось - первого сентября царь пошел в школу и флудить пока не может. ;)

anonymous
()
Ответ на: комментарий от makoven

Не совсем. Здесь все от интерфейсов зависит. Если у тебя USB/RS-232/CAN/ethernet, то все из-под юзверя отлично работает. Если что-то специфичное, может понадобиться модуль ядра. Свой модуль на каждую железку. Аналогично и с юзерспейсом: свой демон на каждую железку. Но можно (если все просто) запилить и 1 демон (с потоками) на всех. Чтобы демоны друг другу не мешали, интерфейс к ним придется сделать отдельным демоном.

Ну, а если у тебя одно приложение на всē про всē, то это удобно тем, что IPC не нужны.

Eddy_Em ☆☆☆☆☆
()

как должна выглядеть модульная система на C.

There has been much talk about component architectures but only one true success: Unix pipes.

loz ★★★★★
()
Ответ на: кофе готово от anonymous

всегда проигрываю с быдла, которое так агрессивно реагирует на употребление слова «кофе» в ср.р.

anonymous
()
Ответ на: комментарий от makoven

ты пытаешься меня обмануть

как блокировки связаны с асинхронностью?

anonymous
()

А что важнее - производительность, надежность, переносимость?

В простейшем случае, если тебе нужно чтоб все модули были постоянно запущены, Менеджером может быть и системд (или свой скрипт, например). Он просто следит за тем, не упал ли какой модуль. Если упал, перезапускает и сообщает об этом

Каждый «модуль» - отдельная программа, общаются между собой именованными каналами. И еще могут посылать сигналы друг другу

Держать все модули в одном процессе может дать экономию ресурсов, но в ущерб надежности. От кривого запроса упал веб-сервер - погасла лампочка и кофеварка

anonymous
()
Ответ на: комментарий от makoven

процессы должны слушать друг друга в обе стороны

Зачем слушать друг друга? Полный дуплекс существенно усложнит архитектуру. Менеджер посылает сигналы с каким-то тактом кофеварке. И получает нолик, если кофе не готово, и единичку по готовности.

Deleted
()
Ответ на: комментарий от makoven

Для этого и нужен тред пул. Полишь в одном потоке, а обрабатываешь наполенное в тред пуле, ставя задачи в очередь.

pon4ik ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.