2013-01-18 20 views
5

我是D新手,正在寫一個簡單的多線程服務器進行練習。在C中啓動客戶端處理程序線程的一個常見範例是將新接受的套接字的文件描述符傳遞給pthread_create(),但是由於sd.concurrency.spawn()不允許我傳遞Socket,因爲它是可變的並可以通過兩個線程訪問。不允許別名爲可變線程本地數據

當然,我實際上並不想要一個不可變的套接字(這就是爲什麼我不想在主線程中強制轉換它,除非必須) - 我想傳遞一個可變的套接字在主線程中超出範圍。我將如何去做這件事?應該(/可以)我使用tid.send(s)讓線程使用套接字?出於某種原因,這對我來說似乎很笨拙。

我現在代碼:

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

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

void clientHandler(Socket s) { 
    ... 
} 

主要生產:錯誤:靜態斷言「別名可變線程本地數據不準。」 ...從這裏實例化:spawn!(Socket)

回答

6

您需要在ClientHandler的插座轉換爲共享,然後再返回

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

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

這樣做的原因是,所有的局部變量都隱含線程本地除非指定shared,並共享或一成不變只能引用作爲參數傳遞給spawn(或send),而東西按值傳遞(沒有引用和基本結構)是好的

,你也應該把接近INT的處理程序與您目前執行的插座很可能會前被關閉的NewL y產卵的線程有機會運行

+0

完美工作,感謝您的額外信息!這是做這種事的慣用方式,還是有更好的辦法?在D中投射感覺很像我做錯事(即與C相反)。 – Dan

+0

@丹最後我檢查了(一年前)'共享'的語義,其中沒有很好的定義,我不知道自那時起改變 –

+1

沒有什麼改變這一點。但是整個D社區都在等待「共享」,以便明確界定。 – DejanLekic

1

這裏的問題不是socket,它是一個局部變量。它是clientHandler,它的聲明你沒有顯示,但顯然它是線程本地的,正如它在錯誤消息中所說的那樣,每個接受的套接字應該有一個新的。提示是「別名」一詞,它是指&運營商。

+0

對不起,我已經通過添加'clientHandler()'的聲明來澄清這個問題。這是一個在全局範圍內聲明的函數,所以也許我比我原先想象的更困惑,但我懷疑它是有問題的線程本地數據。 – Dan

+0

@丹好吧,那是什麼?不是套接字,除非scope()對它有影響,不管它做什麼:我不是'd'專家。 – EJP

+0

'範圍(出口)'確保's.close()'在該範圍的末尾被調用,就像Java中的'finally'關鍵字一樣。無可否認,我添加它並沒有多少意義,但刪除它或將它放在其他位置對編譯錯誤沒有影響。我讀到[全局變量](http://dlang.org/migrate-to-shared.html)會自動轉換爲線程局部變量,但這不適用於函數,並且無論如何用函數替換函數別名(本地,我認爲)lambda表達式也導致相同的錯誤。 – Dan