2011-08-31 36 views
8

Tôi đang cố gắng để hiểu được ví dụ MVAr trong GHC latest docs -Trợ giúp hiểu dụ MVAr trong Haskell

data SkipChan a = SkipChan (MVar (a, [MVar()])) (MVar()) 

newSkipChan :: IO (SkipChan a) 
newSkipChan = do 
    sem <- newEmptyMVar 
    main <- newMVar (undefined, [sem]) 
    return (SkipChan main sem) 

putSkipChan :: SkipChan a -> a -> IO() 
putSkipChan (SkipChan main _) v = do 
    (_, sems) <- takeMVar main 
    putMVar main (v, []) 
    mapM_ (sem -> putMVar sem()) sems 

getSkipChan :: SkipChan a -> IO a 
getSkipChan (SkipChan main sem) = do 
    takeMVar sem 
    (v, sems) <- takeMVar main 
    putMVar main (v, sem:sems) 
    return v 

dupSkipChan :: SkipChan a -> IO (SkipChan a) 
dupSkipChan (SkipChan main _) = do 
    sem <- newEmptyMVar 
    (v, sems) <- takeMVar main 
    putMVar main (v, sem:sems) 
    return (SkipChan main sem) 

Tôi hiểu hầu hết các chương trình nhưng đối với hai câu hỏi -

  1. Are hoạt động như putSkipChan nguyên tử? Dường như tránh chặn trên putMVar bằng cách trước tiên thực hiện takeMVar. Nhưng điều đó sẽ không thành công nếu một cái gì đó khác gọi putMVar sau takeMVar nhưng trước putMVar? Trong những trường hợp như vậy, có vẻ như chương trình sẽ chặn mãi mãi.
  2. Tại sao dupSkipChan nối thêm sem vào danh sách các ẩn dụ trong SkipChan? Điều đó không được thực hiện bởi getSkipChan. Dường như với tôi gọi số dupSkipChan, theo sau là getSkipChan (có vẻ như những gì bạn cần làm để có nhiều người đọc) sẽ gây ra một khối khi putSkipChan cố gắng đánh thức cùng một semaphore hai lần?

Trả lời

5
  1. Bạn là chính xác, thread khác có thể gọi putMVar main và mess lên putSkipChan. Nhưng mô-đun tạo mã ở trên sẽ không xuất ra phương thức khởi tạo SkipChan để một hoạt động giả mạo như vậy sẽ là không thể.

  2. dupSkipChan làm cho một mớiemptyMVar gọi sem và cho biết thêm rằng vào danh sách trong chính. Nó không thêm một từ trước đã được tạo ra trong newSkipChan. Do đó không có khối.

Để giải thích thêm cho người đọc khác của câu hỏi và nhận xét này: Ý tưởng là có thể có nhiều chuỗi trình đọc. Ban đầu, SkipChan main sem1 là người đọc duy nhất. dupSkipChan tạo một SkipChan main sem2. Nếu có hàng ngàn độc giả thì bạn sẽ không muốn thông báo cho tất cả chúng về một giá trị mới trong putSkipChan, do đó thiết kế là getSkipChan đặt danh sách của nó vào danh sách chính. Việc khởi tạo SkipChan được thực hiện trong newSkipChandupSkipChan cũng bao gồm việc đặt số trống mới sem vào danh sách chính.

Khởi tạo và thiết kế ở trên có nghĩa là getSkipChan đầu tiên nhận giá trị gần đây nhất đã được viết (hoặc chặn giá trị đầu tiên đến). Tương lai getSkipChan trên đó SkipChan sẽ luôn nhận được một giá trị mới hơn bất kỳ giá trị nhận được nào trước đó và những giá trị này sẽ không chặn nếu giá trị đó đã có sẵn.

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