2012-08-30 19 views
5

Để làm quen với STM trong Haskell, tôi đã viết các giải pháp sau đây để các vấn đề triết gia ăn:Điều gì là sai với giải pháp sau đây cho "nhà triết học ăn uống"?

import Control.Concurrent 
import Control.Concurrent.STM 
import Control.Monad 
import System.Random 

type Fork = TVar Bool 
type StringBuffer = TChan String 

philosopherNames :: [String] 
philosopherNames = map show ([1..] :: [Int]) 

logThinking :: String -> StringBuffer -> STM() 
logThinking name buffer = writeTChan buffer $ name ++ " is thinking..." 

logEating :: String -> StringBuffer -> STM() 
logEating name buffer = writeTChan buffer $ name ++ " is eating..." 

firstLogEntry :: StringBuffer -> STM String 
firstLogEntry buffer = do empty <- isEmptyTChan buffer 
          if empty then retry 
            else readTChan buffer 

takeForks :: Fork -> Fork -> STM() 
takeForks left right = do leftUsed <- readTVar left 
          rightUsed <- readTVar right 
          if leftUsed || rightUsed 
          then retry 
          else do writeTVar left True 
            writeTVar right True 

putForks :: Fork -> Fork -> STM() 
putForks left right = do writeTVar left False 
         writeTVar right False 

philosopher :: String -> StringBuffer -> Fork -> Fork -> IO() 
philosopher name out left right = do atomically $ logThinking name out 
            randomDelay 
            atomically $ takeForks left right 
            atomically $ logEating name out 
            randomDelay 
            atomically $ putForks left right 

randomDelay :: IO() 
randomDelay = do delay <- getStdRandom(randomR (1,3)) 
       threadDelay (delay * 1000000) 

main :: IO() 
main = do let n = 8 
      forks <- replicateM n $ newTVarIO False 
      buffer <- newTChanIO 
      forM_ [0 .. n - 1] $ \i -> 
       do let left = forks !! i 
        right = forks !! ((i + 1) `mod` n) 
        name = philosopherNames !! i 
       forkIO $ forever $ philosopher name buffer left right 

      forever $ do str <- atomically $ firstLogEntry buffer 
         putStrLn str 

Khi tôi biên dịch và chạy giải pháp của tôi, dường như không có vấn đề đồng thời hiển nhiên tồn tại: Mỗi nhà triết học sẽ cuối cùng ăn và không có nhà triết học nào được ưa thích. Tuy nhiên, nếu tôi loại bỏ các randomDelay báo cáo từ philosopher, biên dịch và chạy, đầu ra của chương trình của tôi trông giống như sau:

1 is thinking... 
1 is eating... 
1 is thinking... 
1 is eating... 
2 is thinking... 
2 is eating... 
2 is thinking... 
2 is eating... 
2 is thinking... 
2 is eating... 
2 is thinking... 

About 2500 lines later... 

2 is thinking... 
2 is eating... 
2 is thinking... 
3 is thinking... 
3 is eating... 
3 is thinking... 
3 is eating... 

And so on... 

gì đang xảy ra trong trường hợp này?

+0

Nếu đây là bài tập về nhà, vui lòng thêm tab bài tập về nhà. – Gray

+0

Nó không phải là bài tập về nhà, tôi đọc về STM trong thế giới thực Haskell và tôi đang cố gắng làm quen với nó. – Alexandros

+0

với thiết lập của tôi (Thử nghiệm Debian 6, ghc 7.4.1, runhaskell/ghc -O2 --make philosophers.hs) Tôi không nghĩ rằng mình có vấn đề - các nhà triết học 1 ..8 đang ăn và suy nghĩ mỗi lần lượt. Phiên bản ghc của bạn là gì và bạn đang biên dịch hay sử dụng ghci? – epsilonhalbe

Trả lời

5

Bạn cần phải biên dịch nó với thời gian chạy ren và kích hoạt rtsopts, và chạy nó với +RTS -N (hoặc +RTS -Nk nơi k là số chủ đề. Cùng với đó, tôi nhận được đầu ra như

8 is eating... 
6 is eating... 
4 is thinking... 
6 is thinking... 
4 is eating... 
7 is eating... 
8 is thinking... 
4 is thinking... 
7 is thinking... 
8 is eating... 
4 is eating... 
4 is thinking... 
4 is eating... 
6 is eating... 
4 is thinking... 

Vấn đề là để một triết gia khác suy nghĩ/ăn uống, một chuyển đổi ngữ cảnh phải xảy ra nếu bạn không có một số chủ đề phần cứng theo cách sắp xếp của bạn. có rất nhiều thời gian để suy nghĩ và ăn nhiều trước khi đến lượt người tiếp theo.

Với đủ chủ đề tại vị trí của bạn, tất cả các nhà triết học có thể đồng thời cố gắng tiếp cận với các nhánh.

+0

Với '+ RTS-N9' (8 chủ đề cho mỗi nhà triết học và 1 cho chủ đề chính, viết cho' stdout'), có vẻ như hai triết gia độc quyền CPU trong một khoảng thời gian cụ thể. – Alexandros

+4

Có bao nhiêu lõi? Không thể có nhiều chủ đề chạy cùng lúc hơn khả năng phần cứng của bạn, vì vậy nếu bạn có một máy lõi kép, không quá hai nhà triết học có thể cạnh tranh cho các nhánh bất cứ lúc nào. –

+0

Tốt hơn nên nghĩ về '-Nk' như kiểm soát số lượng lõi để sử dụng thay vì số lượng chuỗi hệ điều hành. Trong số các trường hợp khác, điều này quan trọng nếu bạn sử dụng 'forkOS' hoặc thực hiện cuộc gọi FFI. –

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