Question

Vous trouverez ci-dessous la source d'un exemple de programme :

Lorsque je l'exécute depuis ghci, printJob et printJob2 fonctionnent correctement et écrivent dix lignes dans un fichier texte.

Mais lorsqu'il est compilé avec l'indicateur -threaded, le programme n'écrit qu'une seule ligne.

J'ai ghc 7.0.3 sur ArchLinux

Voici la commande de compilation :

ghc -threaded -Wall -O2 -rtsopts -with-rtsopts=-N -o testmvar testmvar.hs

Qu'est-ce que je fais de mal ?Pourquoi ça ne marche pas en mode threadé ?

import Control.Concurrent.MVar
import Control.Concurrent (forkIO)
import Control.Exception (bracket)
import Control.Monad (forM_)
import System.IO.Unsafe (unsafePerformIO)
import System.IO (hPutStrLn, stderr)


{-# NOINLINE p #-}
p :: MVar Int
p = unsafePerformIO $ newMVar (1::Int)


{-# NOINLINE printJob #-}
printJob x = bracket (takeMVar p) (putMVar p . (+ 1))
                   (\a -> do
                       appendFile "mvarlog.txt" $ "Input: " ++ x ++ "; Counter: " ++ show a ++ "\n"
                       )


{-# NOINLINE printJob2 #-}
printJob2 = unsafePerformIO $ do
   p2 <- newEmptyMVar
   return $ (\x -> bracket (putMVar p2 True) (\_ -> takeMVar p2)
                   (\_ -> do
                       appendFile "mvarlog.txt" $ "preformed " ++ x ++ "\n"
                   ))

main = do
  forM_ [1..10]
    (\x -> forkIO $ printJob (show x))

MODIFIER:Hammar a souligné que si l'application principale se termine plus tôt que tous les threads générés, ils seront alors tués et il est suggéré d'ajouter un délai à la fin de l'application principale.Je l’ai fait et comme il l’avait prédit, ça marche.

Était-ce utile?

La solution

Le problème est que votre thread principal se termine trop tôt et que lorsque le thread principal d'un programme Haskell se termine, tous les autres threads sont automatiquement supprimés.Selon la façon dont les threads sont planifiés, cela peut se produire avant qu'un des threads ait eu la chance de s'exécuter.

Une solution rapide et sale consiste simplement à ajouter un threadDelay au bout du main, bien qu'une méthode plus robuste consisterait à utiliser une primitive de synchronisation comme un MVar pour signaler quand le thread principal peut se terminer.

Par exemple:

main = do
  vars <- forM [1..10] $ \x -> do
    done <- newEmptyMVar -- Each thread gets an MVar to signal when it's done
    forkIO $ printJob (show x) >> putMVar done ()
    return done

  -- Wait for all threads to finish before exiting
  mapM_ takeMVar vars

Autres conseils

Bien sûr que cela ne fonctionne pas.L'utilisation d'Unsafeperformio revient toujours vous hanter.Structez votre code pour ne pas l'utiliser.L'utilisation pour créer des variables globales n'est pas une utilisation légitime de celle-ci.C'est ce que le lecteur monade est pour.Vous n'avez pas besoin d'unsaferformio pour rien à Haskell.

Cela me tue quand les gens recommandent ce "truc" quand il est clairement cassé.C'est comme l'aveugle qui dirige l'aveugle.Juste ne le faites pas et vous n'aurez pas de problèmes avec haskell.Haskell a des solutions vraiment belles et élégantes à chaque problème que vous jetez, mais si vous insistez pour le combatter au lieu de l'apprendre, vous continuerez toujours à courir dans des insectes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top