2012-05-15 15 views
9
-- thread A 
t <- forkIO $ do 
    _ <- accept listener -- blocks 

-- thread B 
killThread t 

funciona en Linux (probablemente también en OS X y FreeBSD), pero no en Windows (Tratado -enhebrado con RTS + N4 -RTS etc.).¿Puede un hilo del sistema operativo Haskell o Haskell esperando en Network.Socket.accept no ser eliminado en Windows?

  • ¿Cuál es la forma correcta de terminar el hilo A en este caso?
  • ¿Hay alguna manera de tejer la rosca A en un modo especial que permitiría la terminación en el punto que bloquea en accept?
  • ¿Sería útil si A se bifurcaran con forkOS en lugar de forkIO?

Me di cuenta de este comportamiento desviado de Windows cuando me alerté por un bug report.

+2

Relacionado: http://stackoverflow.com/questions/6185189/howto-kill-a-thread-in-haskell –

Respuesta

13

¡Pregunta interesante!

No puede interrumpir el bloqueo de llamadas externas, por lo que estoy algo sorprendido de que pueda interrumpir el hilo en Linux. Además, forkOS no ayuda; eso solo permite que el código externo asigne almacenamiento local de subprocesos, pero no tiene nada que ver con el comportamiento de bloqueo. Pero recordemos que acepta se puede configurar para no bloqueante:

Si no hay conexiones pendientes están presentes en la cola, y el zócalo esté no marcados como sin bloqueo, aceptar() bloquea la persona que llama hasta que la conexión está presente . Si el socket está marcado como no bloqueante y no hay conexiones pendientes en la cola, accept() falla con el error EAGAIN o EWOULDBLOCK.

que es lo que se hace in the Network library for Posix systems. Esto permite entonces la accept a ser interrumpido.

Una nota interesante acerca de Windows:

-- On Windows, our sockets are not put in non-blocking mode (non-blocking 
-- is not supported for regular file descriptors on Windows, and it would 
-- be a pain to support it only for sockets). So there are two cases: 
-- 
-- - the threaded RTS uses safe calls for socket operations to get 
-- non-blocking I/O, just like the rest of the I/O library 
-- 
-- - with the non-threaded RTS, only some operations on sockets will be 
-- non-blocking. Reads and writes go through the normal async I/O 
-- system. accept() uses asyncDoProc so is non-blocking. A handful 
-- of others (recvFrom, sendFd, recvFd) will block all threads - if this 
-- is a problem, -threaded is the workaround. 

Ahora, aceptar en Windows, con el tiempo de ejecución -enhebrado, utiliza accept_safe (que permite a otros hilos para avanzar) - pero no pone el socket en no-bloqueo:

accept [email protected](MkSocket s family stype protocol status) = do 
currentStatus <- readMVar status 
okay <- sIsAcceptable sock 
if not okay 
    then 
    ioError (userError ("accept: can't perform accept on socket (" ++ (show (family,stype,protocol)) ++") in status " ++ 
    show currentStatus)) 
    else do 
    let sz = sizeOfSockAddrByFamily family 
    allocaBytes sz $ \ sockaddr -> do 

#if defined(mingw32_HOST_OS) && defined(__GLASGOW_HASKELL__) 
    new_sock <- 
    if threaded 
     then with (fromIntegral sz) $ \ ptr_len -> 
      throwErrnoIfMinus1Retry "Network.Socket.accept" $ 
      c_accept_safe s sockaddr ptr_len 
     else do 
      paramData <- c_newAcceptParams s (fromIntegral sz) sockaddr 
      rc  <- asyncDoProc c_acceptDoProc paramData 
      new_sock <- c_acceptNewSock paramData 
      c_free paramData 
      when (rc /= 0) 
       (ioError (errnoToIOError "Network.Socket.accept" (Errno (fromIntegral rc)) Nothing Nothing)) 
     return new_sock 

Desde 2005, las versiones del paquete de network, en Windows con -enhebrado utilizar explícitamente aceptar una llamada marcada como safe, permitiendo que otros hilos para hacer progresos, pero no se establece el propio zócalo en modo sin bloqueo (por lo que el hilo llamante bloquea).

Para evitar que veo dos opciones:

  • encontrar la manera de hacer una llamada sin bloqueo aceptar en Windows, y el parche de la biblioteca de red - mirar lo que, por ejemplo, chasquido o yesod hazlo aquí, para ver si ya lo resolvieron.
  • utiliza algún tipo de hilo de supervisión para simular epoll, supervisando los hilos secundarios bloqueados para el progreso.
+0

* ¡Guau! * Gracias a su código, excepto que encontré una buena solución rápida. Vi que con el tiempo de ejecución no subprocesado están haciendo llamadas 'asyncDoProc' y estas pueden ser interrumpidas :) Así que en Windows me limitaré a ese tiempo de ejecución hasta que encuentre una solución mejor. –

+1

Sí, necesitamos que la aceptación no bloqueante esté activada por defecto para Windows. –

+0

También confirmaré y publicaré si realmente puedo interrumpir 'accept' en Linux en este caso particular. –

Cuestiones relacionadas