
akamaus:
Hi, everyone!
I have a function, which sometimes takes a long time to compute or even may loop forever. So I want to limit it in time somehow.
I tried to run it in another thread in order to kill it after its time lapsed. But it seems to lock out other threads so they can't terminate it.
I wonder is there some clever way of dealing with such situation (running a computation in background for specific time) ?
Maybe your loop does no allocations, so the scheduler can't get in and do a context switch. You could put the computation in an external program, and run it over a fork, using unix signals in the external program to kill the computation after a period of time. This is pretty much bullet proof:
import System.Exit import System.Posix.Resource
rlimit = ResourceLimit 3 -- 3 second time limit
main = do setResourceLimit ResourceCPUTime (ResourceLimits rlimit rlimit) ... run my dangerous loop ... exitWith ExitSuccess
And then in the host application:
(out,err,_) <- popen "my_loop_code" [] Nothing return $ case () of {_ | null out && null err -> "Terminated\n" | null out -> err | otherwise -> out }
where popen looks something like:
popen :: FilePath -> [String] -> Maybe String -> IO (String,String,ProcessID) popen file args minput = Control.Exception.handle (\e -> return ([],show e,error (show e))) $ do (inp,out,err,pid) <- runInteractiveProcess file args Nothing Nothing case minput of Just input -> hPutStr inp input >> hClose inp Nothing -> return () output <- hGetContents out errput <- hGetContents err forkIO (Control.Exception.evaluate (length output) >> return ()) forkIO (Control.Exception.evaluate (length errput) >> return ()) waitForProcess pid -- blocks without -threaded, you're warned. return (output,errput,pid)
Cheers, Don