2013-01-18 28 views
5

Tôi mới sử dụng D và tôi đang viết một máy chủ đa luồng đơn giản để thực hành. Một mô hình phổ biến để bắt đầu các chuỗi xử lý máy khách trong C là chuyển qua bộ mô tả tệp của socket mới được chấp nhận() vào pthread_create(), nhưng std.concurrency.spawn() của D sẽ không cho phép tôi truyền Socket vì nó có thể thay đổi được và có thể truy cập bằng hai luồng. Tất nhiên, tôi không thực sự muốn một ổ cắm bất biến (đó là lý do tại sao tôi không thực sự muốn đúc nó trong chủ đề chính trừ khi tôi phải) - Tôi muốn vượt qua một biến thể trong và có nó đi ra khỏi phạm vi trong chủ đề chính. Làm thế nào tôi sẽ đi về điều này? Nên (/ có thể) tôi sử dụng tid.send(s) để cho các chủ đề sử dụng các ổ cắm? Đối với một số lý do mà có vẻ rất clunky với tôi.Bí danh đối với dữ liệu địa lý có thể thay đổi không được phép

Mã của tôi bây giờ là:

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

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

void clientHandler(Socket s) { 
    ... 
} 

nào sản xuất: Lỗi: tĩnh khẳng định "biệt hiệu để dữ liệu thread-địa phương có thể thay đổi không được phép." ... khởi tạo từ đây: đẻ trứng! (Socket)

Trả lời

6

bạn cần phải cast socket để chia sẻ và ngược lại trong ClientHandler

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

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

lý do cho điều này là tất cả các biến địa phương được ngầm sợi địa phương trừ khi xác định shared, và chỉ có tài liệu tham khảo để chia sẻ hoặc bất biến lon được chuyển làm đối số cho spawn (hoặc send) trong khi các công cụ được truyền theo giá trị (cấu trúc không có tham chiếu và nguyên thủy) là tốt

cũng nên đặt trình xử lý gần giống như việc thực hiện hiện tại của bạn. newl y spawned thread có cơ hội chạy

+0

Làm việc một cách hoàn hảo và cảm ơn thông tin bổ sung! Đây có phải là cách thành ngữ để làm điều gì đó như thế này hay là có cách nào tốt hơn? Đúc trong D cảm thấy quyết định như tôi đang làm một cái gì đó sai (ví dụ như trái ngược với C). – Dan

+0

@Dan cuối cùng tôi đã kiểm tra (một năm trước) 'chia sẻ' ngữ nghĩa, nơi không được xác định rõ, tôi không biết nếu điều đó thay đổi kể từ đó –

+1

Không có gì thay đổi liên quan đến điều đó. Nhưng toàn bộ cộng đồng D đang chờ đợi 'chia sẻ' để trở nên rõ ràng. – DejanLekic

1

Vấn đề ở đây không phải là socket, mà là một biến cục bộ. Đó là clientHandler, có khai báo mà bạn không hiển thị, nhưng rõ ràng nó là thread-local như nó nói trong thông báo lỗi, khi cần có một cái mới cho mỗi socket được chấp nhận. Gợi ý là từ 'bí danh', trong đó đề cập đến toán tử &.

+0

Xin lỗi, tôi đã làm rõ câu hỏi bằng cách thêm khai báo 'clientHandler()'. Đó là một hàm được khai báo trong phạm vi toàn cầu, vì vậy có lẽ tôi bối rối hơn tôi nghĩ ban đầu, nhưng tôi nghi ngờ đó là dữ liệu chủ đề địa phương được đề cập. – Dan

+0

@Dan Ok, vậy là gì? Không phải là ổ cắm, trừ khi phạm vi() có một số ảnh hưởng đến điều đó, bất kể nó làm gì: Tôi không có chuyên gia 'd'. – EJP

+0

'phạm vi (thoát)' đảm bảo rằng 's.close()' sẽ được gọi ở cuối phạm vi này, giống như từ khóa 'cuối cùng' trong Java. Phải thừa nhận rằng, nó không làm cho một tấn ý nghĩa mà tôi đã thêm nó, nhưng loại bỏ nó hoặc đặt nó ở nơi khác không có hiệu lực về lỗi biên dịch. Tôi đọc rằng [biến toàn cầu] (http://dlang.org/migrate-to-shared.html) được tự động chuyển đổi thành địa chỉ chuỗi, nhưng không nên áp dụng cho các hàm và ở bất kỳ tỷ lệ nào thay thế bí danh chức năng bằng (địa phương, tôi nghĩ) biểu thức lambda kết quả trong cùng một lỗi là tốt. – Dan

Các vấn đề liên quan