我是Haskell的新手,我无法弄清楚我对Haskell维基上的这个例子不了解:http://www.haskell.org/haskellwiki/Implement_a_chat_server
有问题的具体代码如下:
runConn :: (Socket, SockAddr) -> Chan Msg -> -> IO ()
runConn (sock, _) chan = do
let broadcast msg = writeChan chan msg
hdl <- socketToHandle sock ReadWriteMode
hSetBuffering hdl NoBuffering
chan' <- dupChan chan
-- fork off thread for reading from the duplicated channel
forkIO $ fix $ \loop -> do
line <- readChan chan'
hPutStrLn hdl line
loop
-- read lines from socket and echo them back to the user
fix $ \loop -> do
line <- liftM init (hGetLine hdl)
broadcast line
loop
上面的代码有一个线程同时(可能)写入句柄hdl
,因为另一个线程正在从中读取。这样安全吗?
我怀疑forkIO
(在Haskell内部而不是系统线程库或进程)的性质是使这项工作的原因,但我不确定。
我检查了forkIO的文档是否提到IO句柄 但一无所获。我还检查了System.IO的文档,但没有找到任何关于在不使用锁定的情况下在线程之间使用句柄的提及。
有人告诉我,当文档没有提及有关线程安全的任何内容时,我应该怎么知道这样的事情是否安全?
答案 0 :(得分:3)
forkIO
不是MVar
的本质,而是Chan
的本质,用于实现Handle
和Chan
。
如果您想了解Handle
的工作原理,请参阅Simon Marlow出版的优秀书籍"MVar as building blocks: Unbounded Channels"的第7章中的"Parallel and Concurrent Programming in Haskell"部分。在同一章中,有一个关于forkIO
和MVar
的部分将帮助您了解如何以线程安全的方式实现Chan
。
Chapter 12专门讨论了实现网络服务器的各种方法,包括使用STM而不是{{1}}实现的聊天服务器。
答案 1 :(得分:0)
如果不安全,阻塞插座几乎不可能使用。如果您的协议是异步的并且您正在使用阻塞套接字,那么几乎所有时间都需要在读取时阻塞线程。如果您需要向另一方发送消息,您怎么能这样做?等待对方发给你一条消息?