Wie würden Sie Erlang-ähnliches Senden und Empfangen in C++ implementieren?

StackOverflow https://stackoverflow.com/questions/40423

  •  09-06-2019
  •  | 
  •  

Frage

Tatsächlich scheint diese Frage aus zwei Teilen zu bestehen:

  • Wie implementiert man einen Mustervergleich?
  • So implementieren Sie es senden und Empfangen (d. h.das Actor-Modell)?

Für den Mustervergleichsteil habe ich mir verschiedene Projekte angesehen, z App Und Stütze.Diese sehen ziemlich gut aus, konnten aber auf einer neueren Version (4.x) von g++ nicht zum Laufen gebracht werden.Der Felix Die Sprache scheint auch den Mustervergleich ziemlich gut zu unterstützen, ist aber nicht wirklich C++.

Wie für die Schauspielermodell, es gibt bestehende Implementierungen wie ACT++ und Theron, aber ich konnte nichts außer Papieren zu Ersterem finden, und letzteres ist nur Single-Threaded [siehe Antworten].

Persönlich habe ich Akteure mithilfe von Threading und einer Thread-sicheren Nachrichtenwarteschlange implementiert.Nachrichten sind Hash-ähnliche Strukturen und werden zusammen mit einer Reihe von Präprozessormakros verwendet, um einen einfachen Mustervergleich zu implementieren.

Im Moment kann ich den folgenden Code verwenden, um eine Nachricht zu senden:

(new Message(this))
    ->set("foo", "bar")
    ->set("baz", 123)
    ->send(recipient);

Und das Folgende, um einen einfachen Mustervergleich durchzuführen (qDebug Und qPrintable sind Qt-spezifisch):

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

Allerdings sieht das für mich etwas hackig aus und ist nicht sehr robust.

Wie würdest du es machen?Habe ich vorhandene Arbeiten verpasst?

War es hilfreich?

Lösung

Einer der wichtigen Aspekte von Erlang ist die Art und Weise, wie die Funktionen genutzt werden, um robuste Systeme zu erstellen.

Beim Sende-/Empfangsmodell erfolgt keine gemeinsame Nutzung, sondern explizites Kopieren.Die Prozesse selbst sind leichte Threads.

Wenn Sie die robusten Eigenschaften des Erlang-Modells wünschen, verwenden Sie am besten echte Prozesse und IPC anstelle von Threads.

Wenn Sie jedoch eine robuste Nachrichtenübermittlung wünschen, möchten Sie möglicherweise den Inhalt serialisieren und deserialisieren.Vor allem mit Typensicherheit.

Der Mustervergleich in C++ ist nicht immer schön, aber dafür gibt es ein gutes Muster – am Ende erstellen Sie ein Dispatcher-Objekt, das eine Form von Polymorphismus verwendet, um das zu bekommen, was Sie wollen.

Wenn Sie jedoch nicht aufpassen, erhalten Sie am Ende XML über Pipes :)

Wenn Sie das Erlang-Modell wollen, möchten Sie wirklich Erlang verwenden.Wenn es langsame Teile gibt, können Sie Ihr Programm sicher mit einer fremden Internetfunktion erweitern.

Das Problem bei der Neuimplementierung von Teilen besteht darin, dass Sie keine gute, zusammenhängende Bibliothek und Lösung erhalten.Die Lösungen, die Sie bereits haben, ähneln nicht mehr sehr C++.

Andere Tipps

Was das Schauspielermodell betrifft, so gibt es vorhandene Implementierungen wie ACT ++ und Theron, aber ich konnte nichts anderes als Papiere über die ersteren finden, und letzteres ist nur Single-Threaded.

Als Autor von Theron war ich neugierig, warum Sie glauben, dass es Single-Threaded ist?

Persönlich habe ich Akteure mithilfe von Threading und einer Thread-Safe-Nachrichtenwarteschlange implementiert

So wird Theron umgesetzt.:-)

Asche

Ich implementieren derzeit eine Akteurbibliothek für C++ namens „acedia“ (auf Google gibt es noch nichts darüber), die „Type Matching“ verwendet.Die Bibliothek ist ein Projekt für meine Masterarbeit und man kann damit beliebige Daten an einen Akteur senden.

Ein kleiner Ausschnitt:

recipient.send(23, 12.23f);

Und auf der Empfängerseite können Sie die empfangene Nachricht entweder so analysieren:

Message msg = receive();
if (msg.match<int, float>() { ... }

...Oder Sie können einen Regelsatz definieren, der eine Funktion oder Methode für Sie aufruft:

void doSomething(int, float);

InvokeRuleSet irs;
irs.add(on<int, float>() >> doSomething);
receiveAndInvoke(irs);

Es ist auch möglich, sowohl nach Typ als auch nach Wert zuzuordnen:

Message msg = receive();
if (msg.match<int, float>(42, WILDCARD) { ... }
else if (msg.match<int, float>() { ... }

Die Konstante „WILDCARD“ bedeutet, dass jeder Wert akzeptiert wird.Keine Argumente übergeben ist gleich, alle Argumente auf „WILDCARD“ setzen;Das bedeutet, dass Sie nur die Typen abgleichen möchten.

Dies ist sicherlich ein kleiner Ausschnitt.Sie können auch „Fallklassen“ wie in Scala verwenden.Sie sind vergleichbar mit „Atomics“ in Erlang.Hier ist ein detaillierteres Beispiel:

ACEDIA_DECLARE_CASE_CLASS(ShutdownMessage)
ACEDIA_DECLARE_CASE_CLASS(Event1)
ACEDIA_DECLARE_CASE_CLASS(Event2)

Um auf die definierten Fallklassen zu reagieren, können Sie einen Akteur wie folgt schreiben:

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);
    }

};

Um einen neuen Akteur zu erstellen und zu starten, müssen Sie lediglich Folgendes schreiben:

Acedia::spawn<SomeActor>();

Obwohl die Bibliothek noch nicht einmal das Beta-Stadium erreicht hat, funktionieren die gezeigten Snippets und ich habe eine erste Anwendung darauf ausgeführt.Ein Hauptziel der Bibliothek ist die Unterstützung verteilter Programmierung (auch über ein Netzwerk).

Ihre Frage ist schon eine Weile her, aber wenn Sie daran interessiert sind:lass es mich wissen!:) :)

Sie können das Verhalten mithilfe des Signal-/Slot-Mechanismus von Qt nachahmen, insbesondere da der Signal-/Slot-Mechanismus von Qt Multithread unterstützt.

Ich wäre auf jeden Fall daran interessiert, einen Blick auf Ihre „Acedia“-Bibliothek zu werfen, und würde Ihnen gerne auf jede erdenkliche Weise helfen.Erlang hat einige wunderbare Konstrukte und C++ könnte definitiv von einer solchen Bibliothek profitieren.

Heute habe ich die Bibliothek bei SourceForge gehostet: https://sourceforge.net/projects/acedia/

Wie ich bereits sagte, handelt es sich um eine frühe Veröffentlichung.Aber kritisieren Sie es gerne!

Wenn Sie heute einen robusten Schauspieler im Erlang -Stil in C ++ und das Muster -Matching haben möchten, ist Rost vielleicht die Antwort.

Natürlich gab es das noch nicht öffentlich, als das OP vor ca. 5 Jahren danach fragte, und im April 2014 ist es immer noch nicht Version 1.0 – aber es macht sehr gute Fortschritte und stabilisiert sich definitiv, genug vom Sprachkern ist stabil denken.

Und ok, es ist nicht C++, aber es hat den gleichen Ansatz zur Speicherverwaltung wie C++, außer dass es standardmäßig einfache Aufgaben ohne gemeinsam genutzten Speicher unterstützt (und dann kontrollierte Bibliotheksfunktionen für die gemeinsame Nutzung bereitstellt – „Arc“);Es kann „externe C“-Funktionen direkt aufrufen (und direkt verfügbar machen).Sie können keine vorgefertigten Bibliotheksheader mit C++ teilen – aber Sie können Generika schreiben, die C++-Sammlungsklassen nachahmen (und umgekehrt), um Referenzen auf Datenstrukturen weiterzugeben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top