https://wiki.haskell.org/api.php?action=feedcontributions&user=Frederik&feedformat=atomHaskellWiki - User contributions [en]2024-03-29T12:13:51ZUser contributionsMediaWiki 1.35.5https://wiki.haskell.org/index.php?title=GHC/GHCi_debugger&diff=19407GHC/GHCi debugger2008-02-24T01:06:15Z<p>Frederik: </p>
<hr />
<div>[[Category:GHC|GHCi debugger]]<br />
The GHCi Debugger project extends ghci with basic debugging capabilities. See the GHC user docs for more info.<br />
<br />
== Current status == <br />
The debugger is available in the released [http://www.haskell.org/ghc/download_ghc_681.html GHC 6.8.1]. Full documentation in the [http://www.haskell.org/ghc/dist/current/docs/users_guide/ghci-debugger.html HEAD user docs].</div>Frederikhttps://wiki.haskell.org/index.php?title=Thread-local_storage&diff=5298Thread-local storage2006-08-09T17:48:01Z<p>Frederik: </p>
<hr />
<div>No facility for thread-local storage exists yet in any Haskell compiler.<br />
<br />
If we override 'fork', then we can implement a thread-local storage facility using 'ThreadId'. The following implementation uses one variable per type:<br />
<br />
[http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs]<br />
<br />
However, if many people are going to use thread-local storage then it would be best to have a standard implementation, for library compatibility.<br />
<br />
Simon Marlow and Simon Peyton-Jones have both expressed that they support some form of thread-local storage in the standard libraries.[http://www.haskell.org/pipermail/haskell/2006-March/017658.html][http://www.haskell.org/pipermail/haskell/2006-August/018343.html]<br />
<br />
== Proposal 1 ('threadlocal') ==<br />
<br />
Robert Dockins has put forward a proposal[http://article.gmane.org/gmane.comp.lang.haskell.cafe/11010] which deals specially with initialization issues.<br />
<br />
This deals with initialization which is important if the TLS is used for state.<br />
<br />
== Proposal 2 ==<br />
<br />
Frederik Eaton posted an example API to the Haskell mailing list [http://www.haskell.org/pipermail/haskell/2006-July/018300.html]. It depends on two new functions 'withParams' and 'getParams'.<br />
<br />
(new version 2006/8/9)<br />
<br />
<pre><br />
module Fu.IOParam (<br />
forkIO,<br />
newIOParam,<br />
withIOParam,<br />
getIOParam,<br />
modifyIOParam,<br />
_getParams,<br />
_withParams<br />
) where<br />
<br />
import qualified Data.Map as M<br />
import Data.Maybe<br />
import Data.Unique<br />
import Data.IORef<br />
import Data.Typeable<br />
import Data.Dynamic<br />
import qualified Control.Concurrent as CC<br />
import Control.Concurrent hiding (forkIO)<br />
import Control.Concurrent.MVar<br />
import Control.Exception<br />
import Control.Monad<br />
import System.IO.Unsafe<br />
<br />
type IOParam a = IORef (Unique, a)<br />
<br />
newIOParam :: Typeable a => a -> IO (IOParam a)<br />
newIOParam def = do<br />
k <- newUnique<br />
newIORef (k,def)<br />
<br />
withIOParam :: Typeable v => IOParam v -> v -> IO a -> IO a<br />
withIOParam p value act = do<br />
(k,def) <- readIORef p<br />
m <- _getParams<br />
_withParams (M.insert k (toDyn value) m) act<br />
<br />
getIOParam :: Typeable v => IOParam v -> IO v<br />
getIOParam p = do<br />
(k,def) <- readIORef p<br />
m <- _getParams<br />
let vm = liftM (flip fromDyn $ (error "internal error in IOParam")) $ M.lookup k m<br />
return $ fromMaybe def vm<br />
<br />
-- | convenience function<br />
modifyIOParam :: Typeable v => IOParam v -> (v -> v) -> IO a -> IO a<br />
modifyIOParam p fm act = do<br />
v <- getIOParam p<br />
let v' = fm v<br />
withIOParam p v' act<br />
<br />
forkIO act = do<br />
p <- _getParams<br />
CC.forkIO $ _withParams p act<br />
<br />
----------------------------------------------------------------<br />
-- non-exposed<br />
type ParamsMap = M.Map Unique Dynamic<br />
<br />
_withParams :: ParamsMap -> IO a -> IO a<br />
_withParams newmap act = do<br />
myid <- myThreadId<br />
t <- readMVar threadMap<br />
let oldmap = fromMaybe (M.empty) (M.lookup myid t)<br />
modifyMVar_ threadMap (return . M.insert myid newmap)<br />
act `finally`<br />
modifyMVar_ threadMap (\tm -><br />
if M.null oldmap then<br />
return $ M.delete myid tm<br />
else<br />
return $ M.insert myid oldmap tm)<br />
<br />
_getParams :: IO ParamsMap<br />
_getParams = do<br />
myid <- myThreadId<br />
t <- readMVar threadMap<br />
return $ fromMaybe (M.empty) (M.lookup myid t)<br />
<br />
{-# NOINLINE threadMap #-}<br />
threadMap :: MVar (M.Map ThreadId ParamsMap)<br />
threadMap = unsafePerformIO $ do<br />
-- tid <- myThreadId<br />
-- newMVar $ M.singleton tid M.empty<br />
newMVar $ M.empty<br />
----------------------------------------------------------------<br />
</pre><br />
<br />
=== Comments (feel free to delete) ===<br />
<br />
* Is it possible to set default values for threads where the IOParam was not set?<br />
<br />
:: I'm not sure what this means. You can set a value to ''undefined'' or ''error ...''. You can change the default for a group of threads by setting up new values with ''withIOParam'' and then forking threads from this context.<br />
<br />
* Is it possible to have a value in TLS that is not Typeable?<br />
<br />
:: No, but I think everything should be ''Typeable''.<br />
<br />
* Would the idea be to use unsafePerformIO to create the Uniques for top-level keys?<br />
<br />
:: Please clarify.<br />
<br />
=== Comparison to Proposal 3 ===<br />
<br />
From the mailing list: [http://www.haskell.org/pipermail/haskell/2006-August/018345.html]<br />
<br />
<pre><br />
The main difference between my and your proposals, as I see it, is<br />
that your proposal is based on "keys" which can be used for other<br />
things.<br />
<br />
I think that leads to an interface which is less natural. In my<br />
proposal, the IOParam type is quite similar to an IORef - it has a<br />
user-specified initial state, and the internal implementation is<br />
hidden from the user - yours differs in both of these aspects.<br />
<br />
...<br />
<br />
> * A key issue is this: when forking a thread, does the new thread<br />
> inherit the current thread's bindings, or does it get a<br />
> freshly-initialised set. Sometimes you want one, sometimes the other,<br />
> alas.<br />
<br />
I think the inheritance semantics are more useful and also more<br />
general: If I wanted a freshly-initialized set of bindings, and I only<br />
had inheritance semantics, then I could start a thread early on when<br />
all the bindings are in their initial state, and have this thread read<br />
actions from a channel and execute them in sub-threads of itself, and<br />
implement a 'fork' variant based on this. More generally, I could do<br />
the same thing from a sub-thread of the main thread - I could start a<br />
thread with any set of bindings, and use it to launch other threads<br />
with those bindings. In this way, the "initial" set of bindings is not<br />
specially privileged over intermediate sets of bindings.<br />
</pre><br />
<br />
== Proposal 3 ==<br />
<br />
Simon Peyton-Jones gave another proposal:<br />
<br />
<pre><br />
* The thoughts that Simon and were considering about thread-local state<br />
are quite close to Robert's proposal. For myself, I am somewhat<br />
persuaded that some form of implicitly-passed state in the IO monad<br />
(without explicit parameters) is useful. Examples I often think of are<br />
- Allocating unique identifiers<br />
- Making random numbers<br />
- Where stdin and stdout should go<br />
In all of these cases, a form of dynamic binding is just what we want:<br />
send stdout to the current thread's stdout, use the current thread's<br />
random number seed, etc.<br />
<br />
* There's no need to connect it to *state*. The key top-level thing you<br />
need is to allocate what Adrian Hey calls a "thing with identity".<br />
http://www.haskell.org/hawiki/GlobalMutableState.<br />
I'll call it a key. For example, rather than a 'threadlocal'<br />
declaration, one might just have:<br />
<br />
newkey foo :: Key Int<br />
<br />
where 'newkey' the keyword; this declares a new key with type (Key Int),<br />
distinct from all other keys.<br />
<br />
Now you can imagine that the IO monad could provide operations<br />
withBinding :: Key a -> a -> IO b -> IO b<br />
lookupBinding :: Key a -> IO a<br />
<br />
very much like the dynamic-binding primitives that have popped up on<br />
this thread.<br />
<br />
* If you want *state*, you can have a (Key (IORef Int)). Now you look<br />
up the binding to get an IORef (or MVar, whatever you like) and you can<br />
mutate that at will. So this separates a thread-local *environment*<br />
from thread-local *state*.<br />
<br />
* Keys may be useful for purposes other than withBinding and<br />
thread-local state. One would also want to dynamically create new keys:<br />
newKey :: IO (Key a)<br />
<br />
* I agree with Robert that a key issue is initialisation. Maybe it<br />
should be possible to associate an initialiser with a key. I have not<br />
thought this out.<br />
<br />
* A key issue is this: when forking a thread, does the new thread<br />
inherit the current thread's bindings, or does it get a<br />
freshly-initialised set. Sometimes you want one, sometimes the other,<br />
alas.<br />
</pre><br />
<br />
=== Comments ===<br />
<br />
Keys seem like a mechanism that can help many things. E.g. the<br />
implementation of Typeable. It might be wise to require keys<br />
to be monomorphically typed to solve the polymorphic references problem.<br />
<br />
:Change "Key" to "IODynamicRef" and it's my proposal for dynamic binding. Calling it a "Key" is just funny to me. -- [[User:Taral|Taral]] 16:09, 8 August 2006 (UTC)<br />
<br />
== Monomorphism ==<br />
<br />
It would be nice for TLS not act as unsafeCoerce#. This means that they should be monomorphic. The current status is:<br />
<br />
* TLSVar code - safe<br />
* Proposal 1 - unsafe like global polymorphic IORefs<br />
* Proposal 2 - safe with a runtime check<br />
* Proposal 3 - same as proposal 1.<br />
::If the top-level declaration (newkey) was required to be monomorphic, would that break anything? -- [[User:Taral|Taral]] 16:12, 8 August 2006 (UTC)<br />
<br />
== Cons of Thread local storage ==<br />
<br />
Einar Karttunen expressed concern that extensive use of thread-local storage might cause problems with libraries that run actions in thread pools. He suggested that it would be better to define monads which contain all of the contextual state [http://www.haskell.org/pipermail/haskell/2006-July/018304.html]. Frederik Eaton pointed out that in many reasonable designs, an approach which carries state in custom monads requires code which is quadratic in the number of layers of context [http://www.haskell.org/pipermail/haskell/2006-August/018342.html]. Einar Karttunen also suggested a function which would solve the thread pool problem:<br />
<br />
<pre><br />
-- | Tie all TLS references in the IO action to the current<br />
-- environment rather than the environment it will actually<br />
-- be executed.<br />
tieToCurrentTLS :: IO a -> IO (IO a)<br />
</pre><br />
<br />
[[Category:Proposals]]</div>Frederikhttps://wiki.haskell.org/index.php?title=Thread-local_storage&diff=5297Thread-local storage2006-08-09T17:37:46Z<p>Frederik: </p>
<hr />
<div>No facility for thread-local storage exists yet in any Haskell compiler.<br />
<br />
If we override 'fork', then we can implement a thread-local storage facility using 'ThreadId'. The following implementation uses one variable per type:<br />
<br />
[http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs]<br />
<br />
However, if many people are going to use thread-local storage then it would be best to have a standard implementation, for library compatibility.<br />
<br />
Simon Marlow and Simon Peyton-Jones have both expressed that they support some form of thread-local storage in the standard libraries.[http://www.haskell.org/pipermail/haskell/2006-March/017658.html][http://www.haskell.org/pipermail/haskell/2006-August/018343.html]<br />
<br />
== Proposal 1 ('threadlocal') ==<br />
<br />
Robert Dockins has put forward a proposal[http://article.gmane.org/gmane.comp.lang.haskell.cafe/11010] which deals specially with initialization issues.<br />
<br />
This deals with initialization which is important if the TLS is used for state.<br />
<br />
== Proposal 2 ==<br />
<br />
Frederik Eaton posted an example API to the Haskell mailing list [http://www.haskell.org/pipermail/haskell/2006-July/018300.html]. It depends on two new functions 'withParams' and 'getParams'.<br />
<br />
(new version 2006/8/9)<br />
<br />
<pre><br />
module Fu.IOParam (<br />
forkIO,<br />
newIOParam,<br />
withIOParam,<br />
getIOParam,<br />
modifyIOParam,<br />
_getParams,<br />
_withParams<br />
) where<br />
<br />
import qualified Data.Map as M<br />
import Data.Maybe<br />
import Data.Unique<br />
import Data.IORef<br />
import Data.Typeable<br />
import Data.Dynamic<br />
import qualified Control.Concurrent as CC<br />
import Control.Concurrent hiding (forkIO)<br />
import Control.Concurrent.MVar<br />
import Control.Exception<br />
import Control.Monad<br />
import System.IO.Unsafe<br />
<br />
type IOParam a = IORef (Unique, a)<br />
<br />
newIOParam :: Typeable a => a -> IO (IOParam a)<br />
newIOParam def = do<br />
k <- newUnique<br />
newIORef (k,def)<br />
<br />
withIOParam :: Typeable v => IOParam v -> v -> IO a -> IO a<br />
withIOParam p value act = do<br />
(k,def) <- readIORef p<br />
m <- _getParams<br />
_withParams (M.insert k (toDyn value) m) act<br />
<br />
getIOParam :: Typeable v => IOParam v -> IO v<br />
getIOParam p = do<br />
(k,def) <- readIORef p<br />
m <- _getParams<br />
let vm = liftM (flip fromDyn $ (error "internal error in IOParam")) $ M.lookup k m<br />
return $ fromMaybe def vm<br />
<br />
-- | convenience function<br />
modifyIOParam :: Typeable v => IOParam v -> (v -> v) -> IO a -> IO a<br />
modifyIOParam p fm act = do<br />
v <- getIOParam p<br />
let v' = fm v<br />
withIOParam p v' act<br />
<br />
forkIO act = do<br />
p <- _getParams<br />
CC.forkIO $ _withParams p act<br />
<br />
----------------------------------------------------------------<br />
-- non-exposed<br />
type ParamsMap = M.Map Unique Dynamic<br />
<br />
_withParams :: ParamsMap -> IO a -> IO a<br />
_withParams newmap act = do<br />
myid <- myThreadId<br />
t <- readMVar threadMap<br />
let oldmap = fromMaybe (M.empty) (M.lookup myid t)<br />
modifyMVar_ threadMap (return . M.insert myid newmap)<br />
act `finally`<br />
modifyMVar_ threadMap (\tm -><br />
if M.null oldmap then<br />
return $ M.delete myid tm<br />
else<br />
return $ M.insert myid oldmap tm)<br />
<br />
_getParams :: IO ParamsMap<br />
_getParams = do<br />
myid <- myThreadId<br />
t <- readMVar threadMap<br />
return $ fromMaybe (M.empty) (M.lookup myid t)<br />
<br />
{-# NOINLINE threadMap #-}<br />
threadMap :: MVar (M.Map ThreadId ParamsMap)<br />
threadMap = unsafePerformIO $ do<br />
-- tid <- myThreadId<br />
-- newMVar $ M.singleton tid M.empty<br />
newMVar $ M.empty<br />
----------------------------------------------------------------<br />
</pre><br />
<br />
=== Comments (feel free to delete) ===<br />
<br />
* Is it possible to set default values for threads where the IOParam was not set?<br />
<br />
:: I'm not sure what this means. You can set a value to ''undefined'' or ''error ...''. You can change the default for a group of threads by setting up new values with ''withIOParam'' and then forking threads from this context.<br />
<br />
* Is it possible to have a value in TLS that is not Typeable?<br />
<br />
:: No, but I think everything should be ''Typeable''.<br />
<br />
* Would the idea be to use unsafePerformIO to create the Uniques for top-level keys?<br />
<br />
:: Please clarify.<br />
<br />
=== Comparison to Proposal 3 ===<br />
<br />
From the mailing list: [http://www.haskell.org/pipermail/haskell/2006-August/018345.html]<br />
<br />
<pre><br />
The main difference between my and your proposals, as I see it, is<br />
that your proposal is based on "keys" which can be used for other<br />
things.<br />
<br />
I think that leads to an interface which is less natural. In my<br />
proposal, the IOParam type is quite similar to an IORef - it has a<br />
user-specified initial state, and the internal implementation is<br />
hidden from the user - yours differs in both of these aspects.<br />
<br />
...<br />
<br />
> * A key issue is this: when forking a thread, does the new thread<br />
> inherit the current thread's bindings, or does it get a<br />
> freshly-initialised set. Sometimes you want one, sometimes the other,<br />
> alas.<br />
<br />
I think the inheritance semantics are more useful and also more<br />
general: If I wanted a freshly-initialized set of bindings, and I only<br />
had inheritance semantics, then I could start a thread early on when<br />
all the bindings are in their initial state, and have this thread read<br />
actions from a channel and execute them in sub-threads of itself, and<br />
implement a 'fork' variant based on this. More generally, I could do<br />
the same thing from a sub-thread of the main thread - I could start a<br />
thread with any set of bindings, and use it to launch other threads<br />
with those bindings. In this way, the "initial" set of bindings is not<br />
specially privileged over intermediate sets of bindings.<br />
</pre><br />
<br />
== Proposal 3 ==<br />
<br />
Simon Peyton-Jones gave another proposal:<br />
<br />
<pre><br />
* The thoughts that Simon and were considering about thread-local state<br />
are quite close to Robert's proposal. For myself, I am somewhat<br />
persuaded that some form of implicitly-passed state in the IO monad<br />
(without explicit parameters) is useful. Examples I often think of are<br />
- Allocating unique identifiers<br />
- Making random numbers<br />
- Where stdin and stdout should go<br />
In all of these cases, a form of dynamic binding is just what we want:<br />
send stdout to the current thread's stdout, use the current thread's<br />
random number seed, etc.<br />
<br />
* There's no need to connect it to *state*. The key top-level thing you<br />
need is to allocate what Adrian Hey calls a "thing with identity".<br />
http://www.haskell.org/hawiki/GlobalMutableState.<br />
I'll call it a key. For example, rather than a 'threadlocal'<br />
declaration, one might just have:<br />
<br />
newkey foo :: Key Int<br />
<br />
where 'newkey' the keyword; this declares a new key with type (Key Int),<br />
distinct from all other keys.<br />
<br />
Now you can imagine that the IO monad could provide operations<br />
withBinding :: Key a -> a -> IO b -> IO b<br />
lookupBinding :: Key a -> IO a<br />
<br />
very much like the dynamic-binding primitives that have popped up on<br />
this thread.<br />
<br />
* If you want *state*, you can have a (Key (IORef Int)). Now you look<br />
up the binding to get an IORef (or MVar, whatever you like) and you can<br />
mutate that at will. So this separates a thread-local *environment*<br />
from thread-local *state*.<br />
<br />
* Keys may be useful for purposes other than withBinding and<br />
thread-local state. One would also want to dynamically create new keys:<br />
newKey :: IO (Key a)<br />
<br />
* I agree with Robert that a key issue is initialisation. Maybe it<br />
should be possible to associate an initialiser with a key. I have not<br />
thought this out.<br />
<br />
* A key issue is this: when forking a thread, does the new thread<br />
inherit the current thread's bindings, or does it get a<br />
freshly-initialised set. Sometimes you want one, sometimes the other,<br />
alas.<br />
</pre><br />
<br />
Frederik's response is:<br />
<br />
<pre><br />
The main difference between my and your proposals, as I see it, is <br />
that your proposal is based on "keys" which can be used for other <br />
things. <br />
<br />
I think that leads to an interface which is less natural. In my <br />
proposal, the IOParam type is quite similar to an IORef - it has a <br />
user-specified initial state, and the internal implementation is <br />
hidden from the user - yours differs in both of these aspects. <br />
</pre><br />
<br />
=== Comments ===<br />
<br />
Keys seem like a mechanism that can help many things. E.g. the<br />
implementation of Typeable. It might be wise to require keys<br />
to be monomorphically typed to solve the polymorphic references problem.<br />
<br />
:Change "Key" to "IODynamicRef" and it's my proposal for dynamic binding. Calling it a "Key" is just funny to me. -- [[User:Taral|Taral]] 16:09, 8 August 2006 (UTC)<br />
<br />
== Monomorphism ==<br />
<br />
It would be nice for TLS not act as unsafeCoerce#. This means that they should be monomorphic. The current status is:<br />
<br />
* TLSVar code - safe<br />
* Proposal 1 - unsafe like global polymorphic IORefs<br />
* Proposal 2 - safe with a runtime check<br />
* Proposal 3 - same as proposal 1.<br />
::If the top-level declaration (newkey) was required to be monomorphic, would that break anything? -- [[User:Taral|Taral]] 16:12, 8 August 2006 (UTC)<br />
<br />
== Cons of Thread local storage ==<br />
<br />
Einar Karttunen expressed concern that extensive use of thread-local storage might cause problems with libraries that run actions in thread pools. He suggested that it would be better to define monads which contain all of the contextual state [http://www.haskell.org/pipermail/haskell/2006-July/018304.html]. Frederik Eaton pointed out that in many reasonable designs, an approach which carries state in custom monads requires code which is quadratic in the number of layers of context [http://www.haskell.org/pipermail/haskell/2006-August/018342.html]. Einar Karttunen also suggested a function which would solve the thread pool problem:<br />
<br />
<pre><br />
-- | Tie all TLS references in the IO action to the current<br />
-- environment rather than the environment it will actually<br />
-- be executed.<br />
tieToCurrentTLS :: IO a -> IO (IO a)<br />
</pre><br />
<br />
[[Category:Proposals]]</div>Frederikhttps://wiki.haskell.org/index.php?title=Thread-local_storage&diff=5296Thread-local storage2006-08-09T17:29:28Z<p>Frederik: </p>
<hr />
<div>No facility for thread-local storage exists yet in any Haskell compiler.<br />
<br />
If we override 'fork', then we can implement a thread-local storage facility using 'ThreadId'. The following implementation uses one variable per type:<br />
<br />
[http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs]<br />
<br />
However, if many people are going to use thread-local storage then it would be best to have a standard implementation, for library compatibility.<br />
<br />
Simon Marlow and Simon Peyton-Jones have both expressed that they support some form of thread-local storage in the standard libraries.[http://www.haskell.org/pipermail/haskell/2006-March/017658.html][http://www.haskell.org/pipermail/haskell/2006-August/018343.html]<br />
<br />
== Proposal 1 ('threadlocal') ==<br />
<br />
Robert Dockins has put forward a proposal[http://article.gmane.org/gmane.comp.lang.haskell.cafe/11010] which deals specially with initialization issues.<br />
<br />
This deals with initialization which is important if the TLS is used for state.<br />
<br />
== Proposal 2 ==<br />
<br />
Frederik Eaton posted an example API to the Haskell mailing list [http://www.haskell.org/pipermail/haskell/2006-July/018300.html]. It depends on two new functions 'withParams' and 'getParams'.<br />
<br />
(new version 2006/8/9)<br />
<br />
<pre><br />
module Fu.IOParam (<br />
forkIO,<br />
newIOParam,<br />
withIOParam,<br />
getIOParam,<br />
modifyIOParam,<br />
_getParams,<br />
_withParams<br />
) where<br />
<br />
import qualified Data.Map as M<br />
import Data.Maybe<br />
import Data.Unique<br />
import Data.IORef<br />
import Data.Typeable<br />
import Data.Dynamic<br />
import qualified Control.Concurrent as CC<br />
import Control.Concurrent hiding (forkIO)<br />
import Control.Concurrent.MVar<br />
import Control.Exception<br />
import Control.Monad<br />
import System.IO.Unsafe<br />
<br />
type IOParam a = IORef (Unique, a)<br />
<br />
newIOParam :: Typeable a => a -> IO (IOParam a)<br />
newIOParam def = do<br />
k <- newUnique<br />
newIORef (k,def)<br />
<br />
withIOParam :: Typeable v => IOParam v -> v -> IO a -> IO a<br />
withIOParam p value act = do<br />
(k,def) <- readIORef p<br />
m <- _getParams<br />
_withParams (M.insert k (toDyn value) m) act<br />
<br />
getIOParam :: Typeable v => IOParam v -> IO v<br />
getIOParam p = do<br />
(k,def) <- readIORef p<br />
m <- _getParams<br />
let vm = liftM (flip fromDyn $ (error "internal error in IOParam")) $ M.lookup k m<br />
return $ fromMaybe def vm<br />
<br />
-- | convenience function<br />
modifyIOParam :: Typeable v => IOParam v -> (v -> v) -> IO a -> IO a<br />
modifyIOParam p fm act = do<br />
v <- getIOParam p<br />
let v' = fm v<br />
withIOParam p v' act<br />
<br />
forkIO act = do<br />
p <- _getParams<br />
CC.forkIO $ _withParams p act<br />
<br />
----------------------------------------------------------------<br />
-- non-exposed<br />
type ParamsMap = M.Map Unique Dynamic<br />
<br />
_withParams :: ParamsMap -> IO a -> IO a<br />
_withParams newmap act = do<br />
myid <- myThreadId<br />
t <- readMVar threadMap<br />
let oldmap = fromMaybe (M.empty) (M.lookup myid t)<br />
modifyMVar_ threadMap (return . M.insert myid newmap)<br />
act `finally`<br />
modifyMVar_ threadMap (\tm -><br />
if M.null oldmap then<br />
return $ M.delete myid tm<br />
else<br />
return $ M.insert myid oldmap tm)<br />
<br />
_getParams :: IO ParamsMap<br />
_getParams = do<br />
myid <- myThreadId<br />
t <- readMVar threadMap<br />
return $ fromMaybe (M.empty) (M.lookup myid t)<br />
<br />
{-# NOINLINE threadMap #-}<br />
threadMap :: MVar (M.Map ThreadId ParamsMap)<br />
threadMap = unsafePerformIO $ do<br />
-- tid <- myThreadId<br />
-- newMVar $ M.singleton tid M.empty<br />
newMVar $ M.empty<br />
----------------------------------------------------------------<br />
</pre><br />
<br />
=== Comments (feel free to delete) ===<br />
<br />
* Is it possible to set default values for threads where the IOParam was not set?<br />
<br />
:: I'm not sure what this means. You can set a value to ''undefined'' or ''error ...''. You can change the default for a group of threads by setting up new values with ''withIOParam'' and then forking threads from this context.<br />
<br />
* Is it possible to have a value in TLS that is not Typeable?<br />
<br />
:: No, but I think everything should be ''Typeable''.<br />
<br />
* Would the idea be to use unsafePerformIO to create the Uniques for top-level keys?<br />
<br />
:: Please clarify.<br />
<br />
== Proposal 3 ==<br />
<br />
Simon Peyton-Jones gave another proposal:<br />
<br />
<pre><br />
* The thoughts that Simon and were considering about thread-local state<br />
are quite close to Robert's proposal. For myself, I am somewhat<br />
persuaded that some form of implicitly-passed state in the IO monad<br />
(without explicit parameters) is useful. Examples I often think of are<br />
- Allocating unique identifiers<br />
- Making random numbers<br />
- Where stdin and stdout should go<br />
In all of these cases, a form of dynamic binding is just what we want:<br />
send stdout to the current thread's stdout, use the current thread's<br />
random number seed, etc.<br />
<br />
* There's no need to connect it to *state*. The key top-level thing you<br />
need is to allocate what Adrian Hey calls a "thing with identity".<br />
http://www.haskell.org/hawiki/GlobalMutableState.<br />
I'll call it a key. For example, rather than a 'threadlocal'<br />
declaration, one might just have:<br />
<br />
newkey foo :: Key Int<br />
<br />
where 'newkey' the keyword; this declares a new key with type (Key Int),<br />
distinct from all other keys.<br />
<br />
Now you can imagine that the IO monad could provide operations<br />
withBinding :: Key a -> a -> IO b -> IO b<br />
lookupBinding :: Key a -> IO a<br />
<br />
very much like the dynamic-binding primitives that have popped up on<br />
this thread.<br />
<br />
* If you want *state*, you can have a (Key (IORef Int)). Now you look<br />
up the binding to get an IORef (or MVar, whatever you like) and you can<br />
mutate that at will. So this separates a thread-local *environment*<br />
from thread-local *state*.<br />
<br />
* Keys may be useful for purposes other than withBinding and<br />
thread-local state. One would also want to dynamically create new keys:<br />
newKey :: IO (Key a)<br />
<br />
* I agree with Robert that a key issue is initialisation. Maybe it<br />
should be possible to associate an initialiser with a key. I have not<br />
thought this out.<br />
<br />
* A key issue is this: when forking a thread, does the new thread<br />
inherit the current thread's bindings, or does it get a<br />
freshly-initialised set. Sometimes you want one, sometimes the other,<br />
alas.<br />
</pre><br />
<br />
Frederik's response is:<br />
<br />
<pre><br />
The main difference between my and your proposals, as I see it, is <br />
that your proposal is based on "keys" which can be used for other <br />
things. <br />
<br />
I think that leads to an interface which is less natural. In my <br />
proposal, the IOParam type is quite similar to an IORef - it has a <br />
user-specified initial state, and the internal implementation is <br />
hidden from the user - yours differs in both of these aspects. <br />
</pre><br />
<br />
=== Comments ===<br />
<br />
Keys seem like a mechanism that can help many things. E.g. the<br />
implementation of Typeable. It might be wise to require keys<br />
to be monomorphically typed to solve the polymorphic references problem.<br />
<br />
:Change "Key" to "IODynamicRef" and it's my proposal for dynamic binding. Calling it a "Key" is just funny to me. -- [[User:Taral|Taral]] 16:09, 8 August 2006 (UTC)<br />
<br />
== Monomorphism ==<br />
<br />
It would be nice for TLS not act as unsafeCoerce#. This means that they should be monomorphic. The current status is:<br />
<br />
* TLSVar code - safe<br />
* Proposal 1 - unsafe like global polymorphic IORefs<br />
* Proposal 2 - safe with a runtime check<br />
* Proposal 3 - same as proposal 1.<br />
::If the top-level declaration (newkey) was required to be monomorphic, would that break anything? -- [[User:Taral|Taral]] 16:12, 8 August 2006 (UTC)<br />
<br />
== Cons of Thread local storage ==<br />
<br />
Einar Karttunen expressed concern that extensive use of thread-local storage might cause problems with libraries that run actions in thread pools. He suggested that it would be better to define monads which contain all of the contextual state [http://www.haskell.org/pipermail/haskell/2006-July/018304.html]. Frederik Eaton pointed out that in many reasonable designs, an approach which carries state in custom monads requires code which is quadratic in the number of layers of context [http://www.haskell.org/pipermail/haskell/2006-August/018342.html]. Einar Karttunen also suggested a function which would solve the thread pool problem:<br />
<br />
<pre><br />
-- | Tie all TLS references in the IO action to the current<br />
-- environment rather than the environment it will actually<br />
-- be executed.<br />
tieToCurrentTLS :: IO a -> IO (IO a)<br />
</pre><br />
<br />
[[Category:Proposals]]</div>Frederikhttps://wiki.haskell.org/index.php?title=Thread-local_storage&diff=5255Thread-local storage2006-08-08T12:53:41Z<p>Frederik: </p>
<hr />
<div>No facility for thread-local storage exists yet in any Haskell compiler.<br />
<br />
If we override 'fork', then we can implement a thread-local storage facility using 'ThreadId'. The following implementation uses one variable per type:<br />
<br />
[http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs]<br />
<br />
However, if many people are going to use thread-local storage then it would be best to have a standard implementation, for library compatibility.<br />
<br />
Simon Marlow and Simon Peyton-Jones have both expressed that they support some form of thread-local storage in the standard libraries.[http://www.haskell.org/pipermail/haskell/2006-March/017658.html][http://www.haskell.org/pipermail/haskell/2006-August/018343.html]<br />
<br />
== Proposal 1 ==<br />
<br />
Robert Dockins has put forward a proposal[http://article.gmane.org/gmane.comp.lang.haskell.cafe/11010] which deals specially with initialization issues.<br />
<br />
== Proposal 2 ==<br />
<br />
Frederik Eaton posted an example API to the Haskell mailing list [http://www.haskell.org/pipermail/haskell/2006-July/018300.html]. It depends on two new functions 'withParams' and 'getParams'.<br />
<br />
<pre><br />
import qualified Data.Map as M<br />
import Data.Maybe<br />
import Data.Unique<br />
import Data.IORef<br />
import Data.Typeable<br />
<br />
-- only these 2 must be implemented:<br />
withParams :: ParamsMap -> IO () -> IO ()<br />
getParams :: IO ParamsMap<br />
--<br />
<br />
type ParamsMap = M.Map Unique Value<br />
<br />
data Value = forall a . (Typeable a) => V a<br />
<br />
type IOParam a = IORef (Unique, a)<br />
<br />
newIOParam :: Typeable a => a -> IO (IOParam a)<br />
newIOParam def = do<br />
k <- newUnique<br />
newIORef (k,def)<br />
<br />
withIOParam :: Typeable a => IOParam a -> a -> IO () -> IO ()<br />
withIOParam p value act = do<br />
(k,def) <- readIORef p<br />
m <- getParams<br />
withParams (M.insert k (V value) m) act<br />
<br />
getIOParam :: Typeable a => IOParam a -> IO a<br />
getIOParam p = do<br />
(k,def) <- readIORef p<br />
m <- getParams<br />
return $ fromMaybe def (M.lookup k m >>= (\ (V x) -> cast x))<br />
</pre><br />
<br />
== Proposal 3 ==<br />
<br />
Simon Peyton-Jones gave another proposal:<br />
<br />
<pre><br />
* The thoughts that Simon and were considering about thread-local state<br />
are quite close to Robert's proposal. For myself, I am somewhat<br />
persuaded that some form of implicitly-passed state in the IO monad<br />
(without explicit parameters) is useful. Examples I often think of are<br />
- Allocating unique identifiers<br />
- Making random numbers<br />
- Where stdin and stdout should go<br />
In all of these cases, a form of dynamic binding is just what we want:<br />
send stdout to the current thread's stdout, use the current thread's<br />
random number seed, etc.<br />
<br />
* There's no need to connect it to *state*. The key top-level thing you<br />
need is to allocate what Adrian Hey calls a "thing with identity".<br />
http://www.haskell.org/hawiki/GlobalMutableState.<br />
I'll call it a key. For example, rather than a 'threadlocal'<br />
declaration, one might just have:<br />
<br />
newkey foo :: Key Int<br />
<br />
where 'newkey' the keyword; this declares a new key with type (Key Int),<br />
distinct from all other keys.<br />
<br />
Now you can imagine that the IO monad could provide operations<br />
withBinding :: Key a -> a -> IO b -> IO b<br />
lookupBinding :: Key a -> IO a<br />
<br />
very much like the dynamic-binding primitives that have popped up on<br />
this thread.<br />
<br />
* If you want *state*, you can have a (Key (IORef Int)). Now you look<br />
up the binding to get an IORef (or MVar, whatever you like) and you can<br />
mutate that at will. So this separates a thread-local *environment*<br />
from thread-local *state*.<br />
<br />
* Keys may be useful for purposes other than withBinding and<br />
thread-local state. One would also want to dynamically create new keys:<br />
newKey :: IO (Key a)<br />
<br />
* I agree with Robert that a key issue is initialisation. Maybe it<br />
should be possible to associate an initialiser with a key. I have not<br />
thought this out.<br />
<br />
* A key issue is this: when forking a thread, does the new thread<br />
inherit the current thread's bindings, or does it get a<br />
freshly-initialised set. Sometimes you want one, sometimes the other,<br />
alas.<br />
</pre><br />
<br />
Frederik's response is:<br />
<br />
<pre><br />
The main difference between my and your proposals, as I see it, is <br />
that your proposal is based on "keys" which can be used for other <br />
things. <br />
<br />
I think that leads to an interface which is less natural. In my <br />
proposal, the IOParam type is quite similar to an IORef - it has a <br />
user-specified initial state, and the internal implementation is <br />
hidden from the user - yours differs in both of these aspects. <br />
</pre><br />
<br />
== Cons of Thread local storage ==<br />
<br />
Einar Karttunen expressed concern that extensive use of thread-local storage might cause problems with libraries that run actions in thread pools. He suggested that it would be better to define monads which contain all of the contextual state [http://www.haskell.org/pipermail/haskell/2006-July/018304.html]. Frederik Eaton pointed out that in many reasonable designs, an approach which carries state in custom monads requires code which is quadratic in the number of layers of context [http://www.haskell.org/pipermail/haskell/2006-August/018342.html]. Einar Karttunen also suggested a function which would solve the thread pool problem:<br />
<br />
<pre><br />
-- | Tie all TLS references in the IO action to the current<br />
-- environment rather than the environment it will actually<br />
-- be executed.<br />
tieToCurrentTLS :: IO a -> IO (IO a)<br />
</pre></div>Frederikhttps://wiki.haskell.org/index.php?title=Thread-local_storage&diff=5254Thread-local storage2006-08-08T12:52:35Z<p>Frederik: </p>
<hr />
<div>No facility for thread-local storage exists yet in any Haskell compiler.<br />
<br />
If we override 'fork', then we can implement a thread-local storage facility using 'ThreadId'. The following implementation uses one variable per type:<br />
<br />
[http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs]<br />
<br />
However, if many people are going to use thread-local storage then it would be best to have a standard implementation, for library compatibility.<br />
<br />
Simon Marlow and Simon Peyton-Jones have both expressed that they support some form of thread-local storage in the standard libraries.[http://www.haskell.org/pipermail/haskell/2006-March/017658.html][http://www.haskell.org/pipermail/haskell/2006-August/018343.html]<br />
<br />
== Proposal 1 ==<br />
<br />
Robert Dockins has put forward a proposal[http://article.gmane.org/gmane.comp.lang.haskell.cafe/11010] which deals specially with initialization issues.<br />
<br />
== Proposal 2 ==<br />
<br />
Frederik Eaton posted an example API to the Haskell mailing list [http://www.haskell.org/pipermail/haskell/2006-July/018300.html]. It depends on two new functions 'withParams' and 'getParams'.<br />
<br />
<pre><br />
import qualified Data.Map as M<br />
import Data.Maybe<br />
import Data.Unique<br />
import Data.IORef<br />
import Data.Typeable<br />
<br />
-- only these 2 must be implemented:<br />
withParams :: ParamsMap -> IO () -> IO ()<br />
getParams :: IO ParamsMap<br />
--<br />
<br />
type ParamsMap = M.Map Unique Value<br />
<br />
data Value = forall a . (Typeable a) => V a<br />
<br />
type IOParam a = IORef (Unique, a)<br />
<br />
newIOParam :: Typeable a => a -> IO (IOParam a)<br />
newIOParam def = do<br />
k <- newUnique<br />
newIORef (k,def)<br />
<br />
withIOParam :: Typeable a => IOParam a -> a -> IO () -> IO ()<br />
withIOParam p value act = do<br />
(k,def) <- readIORef p<br />
m <- getParams<br />
withParams (M.insert k (V value) m) act<br />
<br />
getIOParam :: Typeable a => IOParam a -> IO a<br />
getIOParam p = do<br />
(k,def) <- readIORef p<br />
m <- getParams<br />
return $ fromMaybe def (M.lookup k m >>= (\ (V x) -> cast x))<br />
</pre><br />
<br />
Einar Karttunen expressed concern that extensive use of thread-local storage might cause problems with libraries that run actions in thread pools. He suggested that it would be better to define monads which contain all of the contextual state [http://www.haskell.org/pipermail/haskell/2006-July/018304.html]. Frederik Eaton pointed out that in many reasonable designs, an approach which carries state in custom monads requires code which is quadratic in the number of layers of context [http://www.haskell.org/pipermail/haskell/2006-August/018342.html]. Einar Karttunen also suggested a function which would solve the thread pool problem:<br />
<br />
<pre><br />
-- | Tie all TLS references in the IO action to the current<br />
-- environment rather than the environment it will actually<br />
-- be executed.<br />
tieToCurrentTLS :: IO a -> IO (IO a)<br />
</pre><br />
<br />
== Proposal 3 ==<br />
<br />
Simon Peyton-Jones gave another proposal:<br />
<br />
<pre><br />
* The thoughts that Simon and were considering about thread-local state<br />
are quite close to Robert's proposal. For myself, I am somewhat<br />
persuaded that some form of implicitly-passed state in the IO monad<br />
(without explicit parameters) is useful. Examples I often think of are<br />
- Allocating unique identifiers<br />
- Making random numbers<br />
- Where stdin and stdout should go<br />
In all of these cases, a form of dynamic binding is just what we want:<br />
send stdout to the current thread's stdout, use the current thread's<br />
random number seed, etc.<br />
<br />
* There's no need to connect it to *state*. The key top-level thing you<br />
need is to allocate what Adrian Hey calls a "thing with identity".<br />
http://www.haskell.org/hawiki/GlobalMutableState.<br />
I'll call it a key. For example, rather than a 'threadlocal'<br />
declaration, one might just have:<br />
<br />
newkey foo :: Key Int<br />
<br />
where 'newkey' the keyword; this declares a new key with type (Key Int),<br />
distinct from all other keys.<br />
<br />
Now you can imagine that the IO monad could provide operations<br />
withBinding :: Key a -> a -> IO b -> IO b<br />
lookupBinding :: Key a -> IO a<br />
<br />
very much like the dynamic-binding primitives that have popped up on<br />
this thread.<br />
<br />
* If you want *state*, you can have a (Key (IORef Int)). Now you look<br />
up the binding to get an IORef (or MVar, whatever you like) and you can<br />
mutate that at will. So this separates a thread-local *environment*<br />
from thread-local *state*.<br />
<br />
* Keys may be useful for purposes other than withBinding and<br />
thread-local state. One would also want to dynamically create new keys:<br />
newKey :: IO (Key a)<br />
<br />
* I agree with Robert that a key issue is initialisation. Maybe it<br />
should be possible to associate an initialiser with a key. I have not<br />
thought this out.<br />
<br />
* A key issue is this: when forking a thread, does the new thread<br />
inherit the current thread's bindings, or does it get a<br />
freshly-initialised set. Sometimes you want one, sometimes the other,<br />
alas.<br />
</pre><br />
<br />
Frederik's response is:<br />
<br />
<pre><br />
The main difference between my and your proposals, as I see it, is <br />
that your proposal is based on "keys" which can be used for other <br />
things. <br />
<br />
I think that leads to an interface which is less natural. In my <br />
proposal, the IOParam type is quite similar to an IORef - it has a <br />
user-specified initial state, and the internal implementation is <br />
hidden from the user - yours differs in both of these aspects. <br />
</pre></div>Frederikhttps://wiki.haskell.org/index.php?title=Thread-local_storage&diff=5253Thread-local storage2006-08-08T12:50:48Z<p>Frederik: </p>
<hr />
<div>No facility for thread-local storage exists yet in any Haskell compiler.<br />
<br />
If we override 'fork', then we can implement a thread-local storage facility using 'ThreadId'. The following implementation uses one variable per type:<br />
<br />
[http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs]<br />
<br />
However, if many people are going to use thread-local storage then it would be best to have a standard implementation, for library compatibility. <br />
<br />
Robert Dockins has put forward a proposal[http://article.gmane.org/gmane.comp.lang.haskell.cafe/11010] which deals specially with initialization issues.<br />
<br />
Frederik Eaton posted an example API to the Haskell mailing list [http://www.haskell.org/pipermail/haskell/2006-July/018300.html]. It depends on two new functions 'withParams' and 'getParams'.<br />
<br />
<pre><br />
import qualified Data.Map as M<br />
import Data.Maybe<br />
import Data.Unique<br />
import Data.IORef<br />
import Data.Typeable<br />
<br />
-- only these 2 must be implemented:<br />
withParams :: ParamsMap -> IO () -> IO ()<br />
getParams :: IO ParamsMap<br />
--<br />
<br />
type ParamsMap = M.Map Unique Value<br />
<br />
data Value = forall a . (Typeable a) => V a<br />
<br />
type IOParam a = IORef (Unique, a)<br />
<br />
newIOParam :: Typeable a => a -> IO (IOParam a)<br />
newIOParam def = do<br />
k <- newUnique<br />
newIORef (k,def)<br />
<br />
withIOParam :: Typeable a => IOParam a -> a -> IO () -> IO ()<br />
withIOParam p value act = do<br />
(k,def) <- readIORef p<br />
m <- getParams<br />
withParams (M.insert k (V value) m) act<br />
<br />
getIOParam :: Typeable a => IOParam a -> IO a<br />
getIOParam p = do<br />
(k,def) <- readIORef p<br />
m <- getParams<br />
return $ fromMaybe def (M.lookup k m >>= (\ (V x) -> cast x))<br />
</pre><br />
<br />
Einar Karttunen expressed concern that extensive use of thread-local storage might cause problems with libraries that run actions in thread pools. He suggested that it would be better to define monads which contain all of the contextual state [http://www.haskell.org/pipermail/haskell/2006-July/018304.html]. Frederik Eaton pointed out that in many reasonable designs, an approach which carries state in custom monads requires code which is quadratic in the number of layers of context [http://www.haskell.org/pipermail/haskell/2006-August/018342.html]. Einar Karttunen also suggested a function which would solve the thread pool problem:<br />
<br />
<pre><br />
-- | Tie all TLS references in the IO action to the current<br />
-- environment rather than the environment it will actually<br />
-- be executed.<br />
tieToCurrentTLS :: IO a -> IO (IO a)<br />
</pre><br />
<br />
Simon Marlow and Simon Peyton-Jones have both expressed that they support some form of thread-local storage.[http://www.haskell.org/pipermail/haskell/2006-March/017658.html][http://www.haskell.org/pipermail/haskell/2006-August/018343.html]<br />
<br />
Simon Peyton-Jones gave another proposal:<br />
<br />
<pre><br />
* The thoughts that Simon and were considering about thread-local state<br />
are quite close to Robert's proposal. For myself, I am somewhat<br />
persuaded that some form of implicitly-passed state in the IO monad<br />
(without explicit parameters) is useful. Examples I often think of are<br />
- Allocating unique identifiers<br />
- Making random numbers<br />
- Where stdin and stdout should go<br />
In all of these cases, a form of dynamic binding is just what we want:<br />
send stdout to the current thread's stdout, use the current thread's<br />
random number seed, etc.<br />
<br />
* There's no need to connect it to *state*. The key top-level thing you<br />
need is to allocate what Adrian Hey calls a "thing with identity".<br />
http://www.haskell.org/hawiki/GlobalMutableState.<br />
I'll call it a key. For example, rather than a 'threadlocal'<br />
declaration, one might just have:<br />
<br />
newkey foo :: Key Int<br />
<br />
where 'newkey' the keyword; this declares a new key with type (Key Int),<br />
distinct from all other keys.<br />
<br />
Now you can imagine that the IO monad could provide operations<br />
withBinding :: Key a -> a -> IO b -> IO b<br />
lookupBinding :: Key a -> IO a<br />
<br />
very much like the dynamic-binding primitives that have popped up on<br />
this thread.<br />
<br />
* If you want *state*, you can have a (Key (IORef Int)). Now you look<br />
up the binding to get an IORef (or MVar, whatever you like) and you can<br />
mutate that at will. So this separates a thread-local *environment*<br />
from thread-local *state*.<br />
<br />
* Keys may be useful for purposes other than withBinding and<br />
thread-local state. One would also want to dynamically create new keys:<br />
newKey :: IO (Key a)<br />
<br />
* I agree with Robert that a key issue is initialisation. Maybe it<br />
should be possible to associate an initialiser with a key. I have not<br />
thought this out.<br />
<br />
* A key issue is this: when forking a thread, does the new thread<br />
inherit the current thread's bindings, or does it get a<br />
freshly-initialised set. Sometimes you want one, sometimes the other,<br />
alas.<br />
</pre><br />
<br />
Frederik's response is:<br />
<br />
<pre><br />
The main difference between my and your proposals, as I see it, is <br />
that your proposal is based on "keys" which can be used for other <br />
things. <br />
<br />
I think that leads to an interface which is less natural. In my <br />
proposal, the IOParam type is quite similar to an IORef - it has a <br />
user-specified initial state, and the internal implementation is <br />
hidden from the user - yours differs in both of these aspects. <br />
</pre></div>Frederikhttps://wiki.haskell.org/index.php?title=Thread-local_storage&diff=5252Thread-local storage2006-08-08T12:18:26Z<p>Frederik: </p>
<hr />
<div>No facility for thread-local storage exists yet in any Haskell compiler.<br />
<br />
If we override 'fork', then we can implement a thread-local storage facility using 'ThreadId'. The following implementation uses one variable per type:<br />
<br />
[http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs]<br />
<br />
However, if many people are going to use thread-local storage then it would be best to have a standard implementation, for library compatibility. <br />
<br />
Robert Dockins has put forward a proposal[http://article.gmane.org/gmane.comp.lang.haskell.cafe/11010].<br />
<br />
Frederik Eaton posted an example API to the Haskell mailing list [http://www.haskell.org/pipermail/haskell/2006-July/018300.html]. It depends on two new functions 'withParams' and 'getParams'.<br />
<br />
<pre><br />
import qualified Data.Map as M<br />
import Data.Maybe<br />
import Data.Unique<br />
import Data.IORef<br />
import Data.Typeable<br />
<br />
-- only these 2 must be implemented:<br />
withParams :: ParamsMap -> IO () -> IO ()<br />
getParams :: IO ParamsMap<br />
--<br />
<br />
type ParamsMap = M.Map Unique Value<br />
<br />
data Value = forall a . (Typeable a) => V a<br />
<br />
type IOParam a = IORef (Unique, a)<br />
<br />
newIOParam :: Typeable a => a -> IO (IOParam a)<br />
newIOParam def = do<br />
k <- newUnique<br />
newIORef (k,def)<br />
<br />
withIOParam :: Typeable a => IOParam a -> a -> IO () -> IO ()<br />
withIOParam p value act = do<br />
(k,def) <- readIORef p<br />
m <- getParams<br />
withParams (M.insert k (V value) m) act<br />
<br />
getIOParam :: Typeable a => IOParam a -> IO a<br />
getIOParam p = do<br />
(k,def) <- readIORef p<br />
m <- getParams<br />
return $ fromMaybe def (M.lookup k m >>= (\ (V x) -> cast x))<br />
</pre><br />
<br />
Einar Karttunen expressed concern that extensive use of thread-local storage might cause problems with libraries that run actions in thread pools. He suggested that it would be better to define monads which contain all of the contextual state [http://www.haskell.org/pipermail/haskell/2006-July/018304.html]. Frederik Eaton pointed out that in many reasonable designs, an approach which carries state in custom monads requires code which is quadratic in the number of layers of context [http://www.haskell.org/pipermail/haskell/2006-August/018342.html]. Einar Karttunen also suggested a function which would solve the thread pool problem:<br />
<br />
<pre><br />
-- | Tie all TLS references in the IO action to the current<br />
-- environment rather than the environment it will actually<br />
-- be executed.<br />
tieToCurrentTLS :: IO a -> IO (IO a)<br />
</pre><br />
<br />
Simon Marlow and Simon Peyton-Jones have both expressed that they support some form of thread-local storage.[http://www.haskell.org/pipermail/haskell/2006-March/017658.html][http://www.haskell.org/pipermail/haskell/2006-August/018343.html]<br />
<br />
Simon Peyton-Jones gave another proposal:<br />
<br />
<pre><br />
* The thoughts that Simon and were considering about thread-local state<br />
are quite close to Robert's proposal. For myself, I am somewhat<br />
persuaded that some form of implicitly-passed state in the IO monad<br />
(without explicit parameters) is useful. Examples I often think of are<br />
- Allocating unique identifiers<br />
- Making random numbers<br />
- Where stdin and stdout should go<br />
In all of these cases, a form of dynamic binding is just what we want:<br />
send stdout to the current thread's stdout, use the current thread's<br />
random number seed, etc.<br />
<br />
* There's no need to connect it to *state*. The key top-level thing you<br />
need is to allocate what Adrian Hey calls a "thing with identity".<br />
http://www.haskell.org/hawiki/GlobalMutableState.<br />
I'll call it a key. For example, rather than a 'threadlocal'<br />
declaration, one might just have:<br />
<br />
newkey foo :: Key Int<br />
<br />
where 'newkey' the keyword; this declares a new key with type (Key Int),<br />
distinct from all other keys.<br />
<br />
Now you can imagine that the IO monad could provide operations<br />
withBinding :: Key a -> a -> IO b -> IO b<br />
lookupBinding :: Key a -> IO a<br />
<br />
very much like the dynamic-binding primitives that have popped up on<br />
this thread.<br />
<br />
* If you want *state*, you can have a (Key (IORef Int)). Now you look<br />
up the binding to get an IORef (or MVar, whatever you like) and you can<br />
mutate that at will. So this separates a thread-local *environment*<br />
from thread-local *state*.<br />
<br />
* Keys may be useful for purposes other than withBinding and<br />
thread-local state. One would also want to dynamically create new keys:<br />
newKey :: IO (Key a)<br />
<br />
* I agree with Robert that a key issue is initialisation. Maybe it<br />
should be possible to associate an initialiser with a key. I have not<br />
thought this out.<br />
<br />
* A key issue is this: when forking a thread, does the new thread<br />
inherit the current thread's bindings, or does it get a<br />
freshly-initialised set. Sometimes you want one, sometimes the other,<br />
alas.<br />
</pre></div>Frederikhttps://wiki.haskell.org/index.php?title=Thread-local_storage&diff=5251Thread-local storage2006-08-08T12:18:02Z<p>Frederik: </p>
<hr />
<div>No facility for thread-local storage exists yet in an Haskell compiler.<br />
<br />
If we override 'fork', then we can implement a thread-local storage facility using 'ThreadId'. The following implementation uses one variable per type:<br />
<br />
[http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/TLSVar.hs]<br />
<br />
However, if many people are going to use thread-local storage then it would be best to have a standard implementation, for library compatibility. <br />
<br />
Robert Dockins has put forward a proposal[http://article.gmane.org/gmane.comp.lang.haskell.cafe/11010].<br />
<br />
Frederik Eaton posted an example API to the Haskell mailing list [http://www.haskell.org/pipermail/haskell/2006-July/018300.html]. It depends on two new functions 'withParams' and 'getParams'.<br />
<br />
<pre><br />
import qualified Data.Map as M<br />
import Data.Maybe<br />
import Data.Unique<br />
import Data.IORef<br />
import Data.Typeable<br />
<br />
-- only these 2 must be implemented:<br />
withParams :: ParamsMap -> IO () -> IO ()<br />
getParams :: IO ParamsMap<br />
--<br />
<br />
type ParamsMap = M.Map Unique Value<br />
<br />
data Value = forall a . (Typeable a) => V a<br />
<br />
type IOParam a = IORef (Unique, a)<br />
<br />
newIOParam :: Typeable a => a -> IO (IOParam a)<br />
newIOParam def = do<br />
k <- newUnique<br />
newIORef (k,def)<br />
<br />
withIOParam :: Typeable a => IOParam a -> a -> IO () -> IO ()<br />
withIOParam p value act = do<br />
(k,def) <- readIORef p<br />
m <- getParams<br />
withParams (M.insert k (V value) m) act<br />
<br />
getIOParam :: Typeable a => IOParam a -> IO a<br />
getIOParam p = do<br />
(k,def) <- readIORef p<br />
m <- getParams<br />
return $ fromMaybe def (M.lookup k m >>= (\ (V x) -> cast x))<br />
</pre><br />
<br />
Einar Karttunen expressed concern that extensive use of thread-local storage might cause problems with libraries that run actions in thread pools. He suggested that it would be better to define monads which contain all of the contextual state [http://www.haskell.org/pipermail/haskell/2006-July/018304.html]. Frederik Eaton pointed out that in many reasonable designs, an approach which carries state in custom monads requires code which is quadratic in the number of layers of context [http://www.haskell.org/pipermail/haskell/2006-August/018342.html]. Einar Karttunen also suggested a function which would solve the thread pool problem:<br />
<br />
<pre><br />
-- | Tie all TLS references in the IO action to the current<br />
-- environment rather than the environment it will actually<br />
-- be executed.<br />
tieToCurrentTLS :: IO a -> IO (IO a)<br />
</pre><br />
<br />
Simon Marlow and Simon Peyton-Jones have both expressed that they support some form of thread-local storage.[http://www.haskell.org/pipermail/haskell/2006-March/017658.html][http://www.haskell.org/pipermail/haskell/2006-August/018343.html]<br />
<br />
Simon Peyton-Jones gave another proposal:<br />
<br />
<pre><br />
* The thoughts that Simon and were considering about thread-local state<br />
are quite close to Robert's proposal. For myself, I am somewhat<br />
persuaded that some form of implicitly-passed state in the IO monad<br />
(without explicit parameters) is useful. Examples I often think of are<br />
- Allocating unique identifiers<br />
- Making random numbers<br />
- Where stdin and stdout should go<br />
In all of these cases, a form of dynamic binding is just what we want:<br />
send stdout to the current thread's stdout, use the current thread's<br />
random number seed, etc.<br />
<br />
* There's no need to connect it to *state*. The key top-level thing you<br />
need is to allocate what Adrian Hey calls a "thing with identity".<br />
http://www.haskell.org/hawiki/GlobalMutableState.<br />
I'll call it a key. For example, rather than a 'threadlocal'<br />
declaration, one might just have:<br />
<br />
newkey foo :: Key Int<br />
<br />
where 'newkey' the keyword; this declares a new key with type (Key Int),<br />
distinct from all other keys.<br />
<br />
Now you can imagine that the IO monad could provide operations<br />
withBinding :: Key a -> a -> IO b -> IO b<br />
lookupBinding :: Key a -> IO a<br />
<br />
very much like the dynamic-binding primitives that have popped up on<br />
this thread.<br />
<br />
* If you want *state*, you can have a (Key (IORef Int)). Now you look<br />
up the binding to get an IORef (or MVar, whatever you like) and you can<br />
mutate that at will. So this separates a thread-local *environment*<br />
from thread-local *state*.<br />
<br />
* Keys may be useful for purposes other than withBinding and<br />
thread-local state. One would also want to dynamically create new keys:<br />
newKey :: IO (Key a)<br />
<br />
* I agree with Robert that a key issue is initialisation. Maybe it<br />
should be possible to associate an initialiser with a key. I have not<br />
thought this out.<br />
<br />
* A key issue is this: when forking a thread, does the new thread<br />
inherit the current thread's bindings, or does it get a<br />
freshly-initialised set. Sometimes you want one, sometimes the other,<br />
alas.<br />
</pre></div>Frederik