2013-01-18 8 views
5

Ich bin neu in D und ich schreibe einen einfachen Multithread-Server für die Praxis. Ein gängiges Paradigma zum Starten von Client-Handler-Threads in C besteht darin, den Dateideskriptor des neu akzeptierten() ed-Sockets an pthread_create() zu übergeben, aber Ds std.concurrency.spawn() erlaubt es mir nicht, den Socket zu übergeben, weil er veränderbar ist und zugänglich durch zwei Fäden.Aliase zu änderbaren Thread-lokalen Daten nicht erlaubt

Natürlich möchte ich eigentlich keinen unveränderlichen Socket (weshalb ich es nicht wirklich in den Hauptthread werfen möchte, wenn ich nicht muss) - Ich möchte einen veränderlichen einreichen und es haben gehe im Hauptthread aus dem Bereich raus. Wie würde ich darüber gehen? Sollte (/ kann) ich tid.send(s) verwenden, damit der Thread den Socket benutzt? Aus irgendeinem Grund scheint das sehr klobig zu sein.

Mein Code jetzt:

void main() { 
    Socket listener = new TcpSocket; 
    ... 
    for (;;) { 
     Socket s = listener.accept(); 
     scope(exit) s.close(); 

     auto tid = spawn(&clientHandler, s); 
    } 
} 

void clientHandler(Socket s) { 
    ... 
} 

Welche erzeugt: Fehler: statische assert "Aliases zu wandelbar lokalen Thread-Daten erlaubt es nicht." ... instanziiert von hier: spawn! (Socket)

Antwort

6

müssen Sie die Buchse geteilt und wieder zurück in die Clienthandler

auto tid = spawn(&clientHandler, cast(shared) s); 

void clientHandler(shared Socket s) { 
    Socket sock = cast(Socket)s; 
    scope(exit)sock.close(); 
} 

der Grund dafür werfen ist, dass alle lokalen Variablen implizit lokalen Thread werden, es sei denn shared angegeben, und nur Verweise auf gemeinsam genutzten oder unveränderlich Dose als Argument an spawn (oder send) weitergegeben werden, während Zeug nach Wert (Structs ohne Referenzen und Primitiven) übergeben wird

auch sollten Sie den close int den Handler wie bei Ihrer aktuellen Implementierung der Sockel wird wahrscheinlich geschlossen werden, bevor die neul y launched thread hat eine Chance zu laufen

+0

Arbeitete perfekt, und danke für die zusätzlichen Informationen! Ist das der idiomatische Weg, so etwas zu tun, oder gibt es einen besseren Weg? Casting in D fühlt sich entschieden an, als würde ich etwas falsch machen (dh im Gegensatz zu C). – Dan

+0

@Dan zuletzt habe ich überprüft (vor einem Jahr) 'shared' Semantik, wo nicht gut definiert, ich weiß nicht, ob das seit damals geändert –

+1

Nichts in Bezug auf das geändert. Aber die gesamte D-Community wartet darauf, dass 'shared' klar definiert wird. – DejanLekic

1

Das Problem hier ist nicht der Socket, der eine lokale Variable ist. Es ist der clientHandler, dessen Deklaration du nicht gezeigt hast, aber klar ist es thread-lokal wie es in der Fehlermeldung heißt, wenn es pro akzeptiertem Socket einen neuen geben sollte. Der Hinweis ist das Wort "Alias", das sich auf den Operator & bezieht.

+0

Sorry, ich habe die Frage geklärt, indem ich die Deklaration von 'clientHandler()' hinzugefügt habe. Es ist eine Funktion, die im globalen Gültigkeitsbereich deklariert wird, also bin ich vielleicht etwas verwirrter, als ich ursprünglich gedacht habe, aber ich bezweifle, dass es sich um die lokalen Thread-Daten handelt. – Dan

+0

@Dan Ok, also was ist? Nicht der Socket, es sei denn, scope() hat irgendeine Auswirkung auf das, was auch immer es tut: Ich bin kein 'd' Experte. – EJP

+0

'scope (exit)' stellt sicher, dass 's.close()' am Ende dieses Bereichs aufgerufen wird, ähnlich wie das Schlüsselwort 'finally' in Java. Zugegeben, es macht keinen großen Sinn, wo ich es hinzugefügt habe, aber es zu entfernen oder anderswo zu platzieren hat keinen Einfluss auf den Kompilierungsfehler. Ich habe gelesen, dass [globale Variablen] (http://dlang.org/migrate-to-shared.html) automatisch in Thread-Locals konvertiert werden, aber das sollte nicht für Funktionen gelten, und auf jeden Fall den Funktionsalias durch einen ersetzen (lokaler, ich denke) Lambda-Ausdruck führt zu dem gleichen Fehler. – Dan