Как бы вы реализовали Erlang-подобную отправку и получение на C?
Вопрос
На самом деле этот вопрос состоит из двух частей:
- Как реализовать сопоставление с образцом?
- Как реализовать отправлять и получать (т.е.модель Актера)?
Что касается сопоставления шаблонов, я изучал различные проекты, такие как Приложение и Опора.Они выглядят довольно красиво, но заставить их работать в последней версии (4.x) g не удалось. Феликс язык также, кажется, довольно хорошо поддерживает сопоставление с образцом, но на самом деле это не C .
Для Модель актера, существуют существующие реализации, такие как ACT и Терон, но кроме статей о первом я ничего не нашел, а последний является только однопоточным [Посмотри ответы].
Лично я реализовал актеров с использованием потоков и потокобезопасной очереди сообщений.Сообщения представляют собой хеш-подобные структуры, и они используются вместе с рядом макросов препроцессора для реализации простого сопоставления с образцом.
Прямо сейчас я могу использовать следующий код для отправки сообщения:
(new Message(this))
->set("foo", "bar")
->set("baz", 123)
->send(recipient);
И следующее, чтобы выполнить простое сопоставление с образцом (qDebug
и qPrintable
специфичны для Qt):
receive_and_match(m)
match_key("foo") { qDebug("foo: %s", qPrintable(m->value("foo").toString())); }
or_match_key("baz") { qDebug("baz: %d", m->value("baz").toInt()); }
or_match_ignore
end_receive
Однако мне это кажется немного хакерским и не очень надежным.
Как бы вы это сделали?Я пропустил какую-либо существующую работу?
Решение
Одна из важных особенностей erlang — то, как эти функции используются для создания надежных систем.
Модель отправки/получения не предполагает совместного использования и является явным копированием.Сами процессы представляют собой легкие потоки.
Если вам действительно нужны надежные свойства модели Erlang, вам лучше всего использовать реальные процессы и IPC, а не потоки.
Если вам нужна надежная передача сообщений, вы можете в конечном итоге захотеть сериализовать и десериализовать содержимое.Особенно с безопасностью типов.
Сопоставление с образцом в C не всегда красиво, но для этого найдется хороший шаблон — в конечном итоге вы создадите объект-диспетчер, который использует ту или иную форму полиморфизма, чтобы получить то, что вы хотите.
Хотя, если вы не будете осторожны, вы получите xml поверх каналов :)
Действительно, если вам нужна модель Эрланга, вы действительно хотите использовать Эрланг.Если есть медленные биты, я уверен, что вы можете расширить свою программу, используя стороннюю функцию Интернета.
Проблема повторной реализации частей заключается в том, что вы не получите хорошую связную библиотеку и решение.Решения, которые у вас уже есть, больше не похожи на C.
Другие советы
Что касается модели Actor, существуют существующие реализации, такие как ACT и Theron, но я не смог найти ничего, кроме статей о первой, а вторая является только однопоточной.
Как автору «Терона», мне было любопытно, почему вы считаете, что он однопоточный?
Лично я реализовал актеров с использованием потоков и потокобезопасной очереди сообщений.
Вот так реализован Терон..:-)
Пепел
В настоящее время я реализую библиотеку актеров для C под названием «acedia» (в Google пока ничего об этом нет), которая использует «сопоставление типов».Библиотека — это проект моей магистерской диссертации, и с ее помощью вы можете отправлять актеру любые данные.
Небольшой фрагмент:
recipient.send(23, 12.23f);
А на стороне получателя вы можете проанализировать полученное сообщение следующим образом:
Message msg = receive();
if (msg.match<int, float>() { ... }
...или вы можете определить набор правил, который вызывает для вас функцию или метод:
void doSomething(int, float);
InvokeRuleSet irs;
irs.add(on<int, float>() >> doSomething);
receiveAndInvoke(irs);
Также возможно сопоставление как по типу, так и по значению:
Message msg = receive();
if (msg.match<int, float>(42, WILDCARD) { ... }
else if (msg.match<int, float>() { ... }
Константа «WILDCARD» означает, что принимается любое значение.Не передавать аргументы равно, установить для всех аргументов значение «WILDCARD»;это означает, что вы хотите сопоставлять только типы.
Это, конечно, небольшой фрагмент.Также вы можете использовать «кейс-классы», как в Scala.Они сравнимы с «атомикой» в эрланге.Вот более подробный пример:
ACEDIA_DECLARE_CASE_CLASS(ShutdownMessage)
ACEDIA_DECLARE_CASE_CLASS(Event1)
ACEDIA_DECLARE_CASE_CLASS(Event2)
Чтобы реагировать на определенные классы случаев, вы можете написать актера следующим образом:
class SomeActor : public Actor
{
void shutdown() { done = true; }
void handleEvent1();
void handleEvent1();
public:
SomeActor() : done(false) { }
virtual void act()
{
InvokeRuleSet irs;
irs
.add(on<ShutdownMessage>() >> method(&SomeActor::shutdown))
.add(on<Event1>() >> method(&SomeActor::handleEvent1))
.add(on<Event2>() >> method(&SomeActor::handleEvent2))
;
while (!done) receiveAndInvoke(irs);
}
};
Чтобы создать нового актера и запустить его, все, что вам нужно написать, это:
Acedia::spawn<SomeActor>();
Хотя библиотека еще даже не достигла стадии бета-тестирования, показанные фрагменты работают, и у меня есть первое приложение, работающее на ней.Одной из основных целей библиотеки является поддержка распределенного программирования (в том числе по сети).
Ваш вопрос был задан давно, но если он вам интересен:дайте мне знать!:)
Вы можете имитировать это поведение, используя механизм сигнала/слота Qt, тем более что сигнал/слот Qt поддерживает многопоточность.
Мне определенно было бы интересно взглянуть на вашу библиотеку «acedia», и я хотел бы помочь вам, чем смогу.В Erlang есть несколько замечательных конструкций, и C определенно может извлечь выгоду из такой библиотеки.
Сегодня я размещаю библиотеку на sourceforge: https://sourceforge.net/projects/acedia/
Как я уже говорил, это ранний релиз.Но не стесняйтесь критиковать!
Сегодня, если вам нужны надежные актеры в стиле erlang в C и сопоставление с образцом, возможно, Rust — это ответ.
Конечно, когда ОП спросил это примерно 5 лет назад, этого не было публично, и по состоянию на апрель 2014 года это еще не версия 1.0, но она развивается очень хорошо и определенно стабилизируется, достаточное количество языкового ядра стабильно. думать.
И хорошо, это не C, но он имеет тот же подход к управлению памятью, что и C, за исключением того, что он поддерживает легкие задачи без общей памяти по умолчанию (затем предоставляет контролируемые библиотечные функции для совместного использования - «Arc»);Он может напрямую вызывать (и напрямую предоставлять) внешние функции C.Вы не можете использовать заголовки шаблонных библиотек совместно с C, но вы можете написать дженерики, которые имитируют классы коллекций C (и наоборот), чтобы передавать ссылки на структуры данных.