Carcigenicate
Carcigenicate

Reputation: 45826

Haskell is getting deadlocked in a situation it (in theory) shouldn't be

The following yields a deadlock error message (* Exception: thread blocked indefinitely in an MVar operation). I've thought it through step by step, and I don't see the issue.

Meaning (as far as I understand it), it should end up with producer putting something in the MVar, and main waiting to receive something.

If it's getting stuck because listenOn doesn't connect immediately, how can I get around this? The MVar needs to be created in main, and before producer is forked so it can be passed in.

import Control.Concurrent

import Network
import Network.Socket

import System.IO

getSockInfo :: Socket -> IO String
getSockInfo s = do
        info <- getPeerName s
        return $ case info of
            (SockAddrInet port addr) -> "Addr/Port: " ++ (show addr) ++ " / " ++ (show port)
            (SockAddrInet6 port flow addr scope) ->
                "Addr/Port: " ++ (show addr) ++ " / " ++ (show port) ++ "Flow/Scope: " ++ (show flow) ++ " / " ++ (show scope)

producer :: MVar String -> IO ()
producer m = do
    s <- listenOn (PortNumber 5555)
    putStrLn "Listening..."
    info <- getSockInfo s
    putStrLn $ "Connected to " ++ info
    h <- socketToHandle s ReadMode
    loop h m
    where loop h m = do
        message <- hGetLine h
        putMVar m message
        loop h m

main :: IO ()
main = do
    withSocketsDo $ do
        m <- newEmptyMVar
        prod <- forkIO $ producer m
        loop m
        where loop m = do
            n <- takeMVar m
            print n
            loop m

Upvotes: 7

Views: 314

Answers (1)

Ganesh Sittampalam
Ganesh Sittampalam

Reputation: 29110

listenOn returns immediately but doesn't give you a connected socket, so attempts to use it or read from it fail. I'm not sure why you aren't seeing an error message to indicate that, since I do when I run your code. In any case the listening thread is probably dying at that point, which leaves the main thread deadlocked as nothing can write to the MVar.

Using accept after listenOn to wait for a remote connection should fix this.

Upvotes: 4

Related Questions