Как бы вы реализовали Erlang-подобную отправку и получение на С++?
Собственно, этот вопрос состоит из двух частей:
Для части соответствия шаблону я изучал различные проекты, такие как App и Prop. Они выглядят довольно красиво, но не могли заставить их работать с последней версией (4.x) g++. Язык Felix также, похоже, хорошо поддерживает сопоставление с образцом, но на самом деле это не С++.
Что касается модели актера, существуют существующие реализации, такие как ACT ++ и Theron, но я не мог найти ничего, кроме документов о предыдущей <забастовке > , а последний только однопоточный [см. ответы].
Лично я реализовал актеров, использующих потоки и потокобезопасную очередь сообщений. Сообщения являются хэш-подобными структурами и используют их вместе с несколькими макросами препроцессора для реализации простого сопоставления шаблонов.
Сейчас я могу использовать следующий код для отправки сообщения:
(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
Однако это выглядит немного хакерским для меня и не очень надежным.
Как бы вы это сделали? Я пропустил любую существующую работу?
Ответы
Ответ 1
Одна из важных вещей в erlang - это то, как эти функции используются для создания надежных систем.
Модель send/recieve не передает и явно копирует.
Сами процессы - это легкие потоки.
Если вы захотите получить надежные свойства модели erlang, лучше всего использовать реальные процессы и IPC, а не потоки.
Если вам нужна надежная передача сообщений, хотя вам может потребоваться сериализация и десериализация содержимого. Особенно с безопасностью типа.
Совместимость шаблонов в С++ не всегда хороша, но для этого будет хороший шаблон - вы создадите объект диспетчера, который использует какую-то форму полиморфизма, чтобы получить то, что вы хотите.
Хотя если вы не будете осторожны, вы закончите с xml над трубами:)
Действительно, если вы хотите модель erlang, которую вы действительно хотите использовать erlang. Если есть медленные биты, я уверен, что вы можете увеличить свою программу, используя иностранную функцию интернет.
Проблема с повторной реализацией частей, вы не получите хорошую связную библиотеку и решение. Решения, которые вы уже давно не похожи на С++.
Ответ 2
Что касается модели Actor, то есть существующие реализации, такие как ACT ++ и Терон, но я не мог найти ничего, кроме бумаг на первом, и последний только однопоточный.
Как автор Theron, мне было любопытно, почему вы верите в однопоточность?
Лично я реализовал актеров с использованием нарезки резьбы и поточной защиты очередь сообщений
То, как работает Theron..: -)
Зола
Ответ 3
В настоящее время я реализую библиотеку актеров для С++ под названием "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"; это означает, что вы хотите только соответствовать типам.
Это, конечно, небольшой фрагмент. Также вы можете использовать "классы case", как в 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>();
Хотя библиотека даже не достигла бета-стадиона, показанные фрагменты работают, и у меня есть первое приложение, работающее на нем. Одной из основных целей библиотеки является поддержка распределенного программирования (также по сети).
Ваш вопрос давно, но если вам это интересно: дайте мне знать!:)
Ответ 4
Вы можете имитировать поведение с использованием механизма сигнала/слота Qt, тем более, что сигнал/слот Qt поддерживает многопоточность.
Ответ 5
Я определенно был бы заинтересован в том, чтобы посмотреть на вашу библиотеку "acedia" и хотел бы помочь в любом случае, каким мог. У Erlang есть несколько замечательных конструкций, и С++ определенно может извлечь выгоду из такой библиотеки.
Ответ 6
Сегодня я устанавливаю библиотеку в sourceforge: https://sourceforge.net/projects/acedia/
Как я уже говорил, это ранний выпуск. Но не стесняйтесь критиковать его!
Ответ 7
Сегодня, если вы хотите, чтобы стили erlang были устойчивыми актерами на С++ и сопоставлением с образцом,
может быть, Rust - это ответ.
Конечно, это было не публично, когда OP спросил ~ 5 лет назад, и с апреля 2014 года он все еще не является v1.0, но он развивается очень хорошо и определенно стабилизируется, достаточно ядра языка я думаю.
И хорошо его не С++, но он имеет тот же подход к управлению памятью, что и С++, за исключением того, что он поддерживает легкие задачи без общей памяти по умолчанию (затем предоставляет управляемые библиотечные функции для совместного использования - "Arc" );
Он может напрямую вызывать (и напрямую выставлять) функции "extern C". Вы не можете делиться шаблонами заголовков библиотек с С++, но вы можете писать обобщения, которые сопоставляют классы коллекции С++ (и vica versa), чтобы передавать ссылки на структуры данных.