2012-01-02 33 views
11

Bạn có hai luồng, a và b. Thread a nằm trong vòng lặp mãi mãi, lắng nghe trên socket chặn 1. Thread b cũng nằm trong vòng lặp mãi mãi, lắng nghe trên socket socket 2. Cả socket 1 và socket 2 đều có thể trả về dữ liệu bất kỳ lúc nào, vì vậy Thread a có thể ngủ mãi mãi chờ đợi dữ liệu trong khi Thread b liên tục lấy dữ liệu từ socket và tiếp tục với quá trình xử lý của nó. Đó là nền tảng.Chủ đề Mô hình Truyền thông Chủ đề Haskell

Bây giờ giả sử họ cần chia sẻ một từ điển. Khi Thread a lấy một số dữ liệu (nếu có) nó sẽ thêm một cặp giá trị khóa vào từ điển sau khi xử lý một số, và sau đó tiếp tục chờ đợi thêm dữ liệu. Khi Thread b nhận dữ liệu từ socket của nó, đầu tiên nó sẽ truy vấn từ điển để xem có thông tin liên quan đến dữ liệu mà nó đã nhận trước khi tiếp tục với quá trình xử lý của nó hay không. Không có xóa cho từ điển, chỉ chèn và truy vấn (Tôi muốn được quan tâm nếu điều này làm cho một sự khác biệt trong các giải pháp cuối cùng).

Trong ngôn ngữ chuẩn bắt buộc như python hoặc c, điều này khá dễ thực hiện bằng cách đặt từ điển sẵn có ở cả hai phạm vi và chỉ truy vấn từ sau khi chuỗi đã có khóa.) cập nhật từ điển.

Trong Haskell, tôi dường như đang vật lộn để đưa ra một triển khai tốt về mẫu này. MVars, chỉ có thể có một mục tại một thời điểm, vì vậy nó không thể là Thread được đặt trong từ điển, vì bản cập nhật mới có thể xảy ra và nó sẽ không thể đẩy từ điển mới cho đến khi Thread b lấy nó từ MVar. Mặt khác, nếu thread b sử dụng một MVar để gửi tín hiệu sẵn sàng "ok!" vào luồng a, có thể là trường hợp mà Thread a đang ngủ trên ổ cắm đọc của nó, vì vậy nó sẽ không thể gửi dữ liệu trở lại cho đến khi socket được bỏ chặn của nó được bỏ chặn! Ngoài ra còn có các kênh, nhưng điều đó có vẻ lộn xộn vì tôi sẽ phải tiếp tục gửi các bộ từ điển mới và Chủ đề B sẽ loại bỏ tất cả trừ những cái cuối cùng.

Giải pháp thay thế có thể hoạt động là chỉ cần gửi cập nhật xuống kênh và yêu cầu B tạo từ điển cho chính nó. Tuy nhiên tôi tự hỏi nếu có giải pháp thay thế tốt hơn.

Cảm ơn bạn đã dành thời gian đọc câu hỏi rất dài này!

+4

Tôi không thấy vấn đề với 'MVar'. Nếu A được đánh thức và nhận dữ liệu mới, nó sẽ cố gắng 'takeMVar' từ điển từ' MVar'.Khi nó thành công, hãy cập nhật từ điển, từ điển 'putMVar', trở lại chế độ ngủ. Khi B nhận dữ liệu, hãy thử 'takeMVar', tra cứu xem lại. Nó bị hỏng ở đâu? –

+1

Cảm ơn! Bắn Xin lỗi đó là chính xác những gì tôi đang tìm kiếm, không bao giờ. Tôi vẫn còn là một người bắt đầu. Tôi đã nghĩ rằng nó không thể lấy ra nếu nó được đưa vào, và chỉ có một sợi khác có thể. Giả định ngu ngốc ở sau đầu tôi! Tôi không chắc chắn làm thế nào để đóng câu hỏi này ngay bây giờ? –

+0

Tôi có thể làm cho nó một câu trả lời mà bạn có thể chấp nhận để đánh dấu vấn đề là giải quyết, hoặc bạn có thể xóa câu hỏi nếu bạn thích (Tôi không biết làm thế nào, nên có một liên kết xóa ở đâu đó, tôi tin). –

Trả lời

10

Bạn có thể sử dụng một MVar theo cách sau:

  • Khi thread A nhận dữ liệu mới, nó sẽ cố gắng để có được những điển với takeMVar. Khi thành công, nó sẽ cập nhật từ điển và đặt nó trở lại vào MVar
  • Khi chuỗi B nhận dữ liệu, nó sẽ cố gắng lấy từ điển với takeMVar - trong trường hợp trên, ở đó hiếm khi nhận dữ liệu thành công trung bình khá nhanh. Sau đó, nó tra cứu và đặt lại từ điển.

Vì hammar đã chỉ ra, có thể tốt hơn là không sử dụng trực tiếp takeMVarputMVar mà thay vào đó hãy bọc chúng trong modifyMVar_ resp. modifyMVar không để trống MVar nếu một chuỗi bị ngoại lệ trong khi sử dụng từ điển.

Trong chủ đề A, cái gì đó như

modifyMVar_ mvar (\dict -> putMVar mvar (insert newStuff dict)) 

trong chủ đề B tất cả bạn cần là một đơn giản readMVar (nhờ @hammar một lần nữa đã chỉ mà ra).

+0

Đối với chủ đề B, tôi nghĩ rằng một 'readMVar' sẽ đủ (và có thể hiệu quả hơn), vì từ điển không được cập nhật. – hammar

+0

Có thể. Nó rất không chắc rằng nó bị ảnh hưởng bởi một ngoại lệ giữa việc lấy và đặt, nhưng không phải là không thể. Sau đó, 'MVar' có thể kết thúc rỗng. Mặt khác, hoàn toàn có thể là một ngoại lệ sẽ phải giết toàn bộ quá trình. –

+0

Việc thực hiện 'readMVar' sử dụng' mask_', vì vậy tôi không nghĩ rằng một ngoại lệ _can_ xảy ra giữa việc lấy và đặt. – hammar