Hilfe bei Atomics benötigt



  • 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?



  • Ein strand sorgt dafür, dass niemals zwei Handler zur selben Zeit aufgerufen werden. Wozu habe ich dann mehrere Threads, wenn die eh nicht parallel aufgerufen werden? Das ist einfach fail per Design.



  • Kellerautomat schrieb:

    Ein strand sorgt dafür, dass niemals zwei Handler zur selben Zeit aufgerufen werden. Wozu habe ich dann mehrere Threads, wenn die eh nicht parallel aufgerufen werden? Das ist einfach fail per Design.

    Du sollst ja auch nicht pauschal alle Handler durch einen Strand jagen, sondern nur die, in denen auf geteilte Ressourcen zugegriffen wird.

    In Deinem Fall brauchst Du z.B. in Deinem (nicht über einen Strand synchroniserten) Accept-Handler sowas wie:

    void server::handle_accept(boost::system::error_code const & ec)
    {
    	client_ptr_t new_client(new client(socket)); //client erzeugen
    	//...
    	//neben remove_client die einzige operation die vermutlich durch den strand gehen muss...
    	acceptor.get_io_service().post(strand.wrap(boost::bind(&server::enlist_client, this, new_client)));
    }
    


  • Kellerautomat schrieb:

    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.

    Folgende Fragen: warum mehrere Threads? Wonach werden die erstellt?
    Wonach wird der Besitz des Sockets entschieden?
    Wonach wird entschieden welcher Thread vom Socket liest?



  • Shade Of Mine schrieb:

    Folgende Fragen: warum mehrere Threads? Wonach werden die erstellt?
    Wonach wird der Besitz des Sockets entschieden?
    Wonach wird entschieden welcher Thread vom Socket liest?

    Das macht asio für Dich. Du startest in mehreren Threads io_service::run für das gleiche io_service -Objekt, und und asio sorgt dann dafür, dass aktivierte Handler auf freie Threads verteilt werden.



  • Shade Of Mine schrieb:

    warum mehrere Threads?

    - Damit der Server besser skaliert
    - Weil ich Erfahrungen mit Threads sammeln will

    Shade Of Mine schrieb:

    Wonach werden die erstellt?

    In der Config lässt sich einstellen, wie viele Threads der Server verwenden soll.

    Shade Of Mine schrieb:

    Wonach wird der Besitz des Sockets entschieden?

    Der schnellste Thread gewinnt.

    Shade Of Mine schrieb:

    Wonach wird entschieden welcher Thread vom Socket liest?

    Das macht boost.asio für mich.



  • Alles klar.

    Dann ist das eine Frage des asio Handlings. Da gibts sicher etwas das genau dafür gemacht wurde.



  • Mir ist da gerade was in den Kopf gekommen, wovon ich vermute, dass ich es euch nicht so verdeutlicht habe. Also: Der Besitzer des Sockets gilt nur für eine Gruppe an Schreibvorgängen. Sobald diese abgeschlossen sind, gibt es keinen Besitzer mehr. Bei jeder neuen Gruppe wird ein neuer Besitzer gewählt.



  • Shade Of Mine schrieb:

    genau dafür

    Wofür?


Anmelden zum Antworten