Как бы вы реализовали 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), чтобы передавать ссылки на структуры данных.