Hilfe bei Atomics benötigt



  • Man könnte sagen, der Wert der Variable besagt, ob gerade ein Thread den Socket besitzt. Sprich:
    false -> Ich bin derjenige, der selbst schreiben muss.
    true -> Ein anderer schreibt gerade, ich kann das schreiben meiner Nachricht einfach an ihn delegieren.



  • OK, das musst du mehr erklaeren. Du sharest sockets zwischen mehreren threads?



  • Nein, eben nicht. Genau das verhindere ich doch mit der Variable.



  • Kellerautomat schrieb:

    Nein, eben nicht. Genau das verhindere ich doch mit der Variable.

    Du musst mehr erklaeren. Das was ich bisjetzt verstanden habe klingt furchtbar konfus. Bitte skizziere dein Design hier auf.

    Denn entweder verstehe ich dich nicht richtig oder mit deinem Design hats was gravierendes.



  • Uff. Ich weiß wirklich nicht, wie ich das skizzieren soll, oder was überhaupt. Ich versuche mal, den Ablauf Schritt für Schritt zu erklären.

    Logischerweise darf nur ein Thread an einem Socket schreiben. Diesen nenne ich im folgenden den Besitzer des Sockets.

    Nun kommen mehrere Threads an der Funktion write_line an. Irgendwie muss entschieden werden, wer der Besitzer wird und andere Threads müssen darüber informiert werden, dass es einen Besitzer gibt. Dazu überprüft jeder Thread die Variable writing und setzt sie atomar auf true, wenn sie false ist. Der schnellste Thread übernimmt also den Besitz. Dieser Thread beginnt mit dem schreiben seiner eigenen Nachricht und danach schreibt er alle anderen Nachrichten aus der Queue, bis diese leer ist.

    Für alle anderen Threads schlägt diese Operation fehl. Sie werfen ihre Nachrichten nur in die Queue hinein und delegieren damit das Schreiben an den besitzenden Thread.



  • Warum hast du mehrere Threads?
    Warum ist das nicht schon von vornherein definiert wer Schreiben darf und wer in die Queue wirft?



  • Shade Of Mine schrieb:

    Warum hast du mehrere Threads?

    Weil da das Problem ein noch viel größeres wäre. Wenn nur irgendwas blockiert, ist der Server lahmgelegt. Davon abgesehen: Skalierbarkeit.

    Shade Of Mine schrieb:

    Warum ist das nicht schon von vornherein definiert wer Schreiben darf und wer in die Queue wirft?

    boost.asio wählt die Handler-Threads auf eine unbekannte Weise aus, ich nenne es mal zufällig. Wüsste nicht, warum oder wie ich da einen Besitzer festlegen könnte/sollte. Jeder Thread könnte an jeden User eine Nachricht senden müssen.



  • wenn du eh eine Queue für zu versendende Nachrichten hast, wieso stellst du nicht einen Thread rein für das Schreiben ab und die restlichen Threads pushen nur ihre Nachrichten in die Queue.

    Aber wiso hast du nur einen Socket? AFAIK existiert auf Serverseite für jeden Netzwerkclient ein eigener Socket (z.b. unter POSIX/Linux liefert accept diesen socket zurück)

    Und ich vermute das es in boost.asio auch nicht anders ist.



  • Du hast meine Frage nicht beantwortet.

    Mich interessieren keine Implementierungsdetails 😉 Ich will wissen warum du mehrere Threads hast.

    PS:
    Dein Design ist ungewoehnlich. Deshalb musst du jetzt entweder darauf vertrauen dass du alles richtig gemacht hast oder hier dein Design skizzieren. Sonst fuehrt das hier zu nichts.



  • Ach ja in der boost.asio Dokumentation gibt es auch ein chat example
    http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/examples.html



  • @firefly: Natürlich hab ich pro Client einen Socket (+ eine Queue + den atomic_bool).

    @SoM: Du sagst einerseits, Implementierungsdetails interessieren dich nicht, andererseits möchtest du, dass ich das Design skizziere. Was genau willst du sehen?



  • Design != Implementierungsdetails *g*

    Aber dann gibt es doch kein synchronistationsproblem beim Schreiben auf den Socket. Das einzige was du synchronisieren musst ist der Zugriff auf die Queue. Und zwar wenn von einem Client eine Nachricht an einen anderen Client geschickt werden soll. (Der Serverpart von Client A packt die Nachricht an Client B in dessen Queue auf Serverseite)



  • Ich habe ja auch nicht gesagt, dass es ein Synchronisierungsproblem auf den Sockets gibt. Das ist durch die Besitzerwahl bereits ausgeschlossen.

    Die Queue ist eine tbb::concurrent_queue aus den Intel Thread Building Blocks und damit bereits thread-safe.



  • @SoM:

    Der Server hat:
    - Einen Acceptor zum annehmen von Verbindungen sowie einen accept-handler, der die Clients konstruiert und in eine Liste reinwirft.
    - Die Clientliste
    - Einen Threadpool
    - Einen Handler für Clientnachrichten

    Ein Client hat:
    - Einen Socket, die Message-Queue für ausgehende Nachrichten, sowie den atomic_bool für die Besitzerwahl
    - Einen handler für gelesene Nachrichten, der wiederum den Handler am Server aufruft
    - Einen write-handler, der aufgerufen wird, sobald eine Nachricht vollständig geschrieben wurde
    - Die Funktion, um eine Nachricht zu senden

    server                 client
    +--------------------+ +---------------+
    | accept-handler     | | socket        |
    | acceptor           | | writing-bool  |
    | thread-pool        | | message-queue |
    | clients            | | write-handler |
    | client-msg-handler | | read-handler  |
    +--------------------+ | write-line    |
                           +---------------+
    

    Wenn es das nicht ist, was du hören wolltest, dann erklärs mir bitte.



  • Wir sind also noch kein Stueck weiter ... irgendwie habe ich das erwartet ...



  • Kellerautomat schrieb:

    Wenn es das nicht ist, was du hören wolltest, dann erklärs mir bitte.

    Ich hätte gerne sowas:

    Es gibt User und Channel. Ein Channel hat 1-N User mit sich verbunden und ein User kann in N Channel sein.

    Wenn ein User sich zum Server connected wird ein Thread erstellt der die Kommunikaion mit dem User übernimmt. Wenn nun User A in Channel C eine Nachricht schreibt (oder den Channel leavt, etc.), muss das an alle anderen User in dem Channel gepusht werden. Dazu gibt es ein Observer Pattern wo jeder User Thread sich als Observer zu einem Channel hinzufügt. Wenn nun die Nachricht gepusht wird, werden alle User-Threads darüber informiert. Diese haben jeweils eine Queue um die Menge an gepushten Nachrichten aufzufangen und diese der Reihe nach abarbeiten zu können.

    So in etwa würde ich eine naive Chat-Server implementierung machen.

    Wenn wir zB dieses Modell hätten - dann würde man nur die User-Queue irgendwie schützen müssen, zB indem man eine synchronisierte Liste verwendet oder eine Lockfree Queue oder etwas derartiges. Und fertig ist die Synchronisation.



  • Ihr könntet auch einfach konkret werden, das würde alles wesentlich vereinfachen.

    Edit: Zu spät.



  • Wieso benutzt Du nicht einfach strands? Bei boost.asio ist das eigentlich der natürliche Weg, um Resourcen gegen Races zu schützen. Das bedeutet natürlich auch, dass Du dich von den synchronen Operationen verabschieden musst, aber das sollte man bei boost.asio eh.



  • strands verhindern doch Parallelität. Das ist Mist.

    @SoM: Also, hier goes:
    Es gibt Channel und User. :p
    In jedem Channel können beliebig viele User sein (auch 0). Wenn sich ein User zum Server connected, wird eine asynchrone Lese-Operation gestartet. Sobald der User etwas sendet, wird von einem der Server-Threads ein Handler aufgerufen, der die Nachricht verarbeitet. Wenn an einen User mehrere Nachrichten aus verschiedenen Threads gesendet werden sollen, gibt es immer einen besitzenden Thread, der schreibt. Die Anderen Threads werfen ihre Nachrichten für den besitzer-Thread in eine Queue, die von ihm abgearbeitet wird.



  • Kellerautomat schrieb:

    strands verhindern doch Parallelität. Das ist Mist.

    Synchronisieren verhindert parallelität. Entweder Du musst synchen, oder eben nicht. Was denn nun?


Anmelden zum Antworten