views:

135

answers:

2
let info = new SortedDictionary<string, string>

...

Thread A
--------
info.Add("abc", "def")

Thread B
--------
info
|> Seq.iteri (fun i value ->  ...

Where do I place the readLock when I use the iteri function?

+1  A: 

You may want to just side-step the problem of mutability, and use an immutable Map instead of SortedDictionary. This way, your iteration works on a "snapshot" of the data structure, with no worries about it getting changed out from underneath you. Then, you only need to lock your initial grab of the snapshot.

For example (warning, have not tested to see if this is actually threadsafe!):

let mymap = ref Map<string,string>.Empty

let safefetch m = lock(m) (fun () -> !m)
let safeadd k v m = lock(m) (fun () -> m := Map.add k v !m)

mymap
|> safefetch
|> Map.iter ( fun k v -> printfn "%s: %s" k v )

mymap |> safeadd "test" "value"
James Hugard
Wouldn't the lock be released that is set in safefetch right before Map.iter starts?
Moonlight
One of the issues with a Map is how to pass it from one thread to a Dispatcher in another thread? Each modification will give a different map. Unless I implement a mailbox I do not see how to pass it along. A closure perhaps?
Moonlight
A: 

After some thinking it seems that placing a lock on Seq.iteri does actually make no sense since a Seq is lazy in F#.

However it is interesting to note that an exception is thrown when additional elements of a dictionary are inserted by another thread during the iteration of the sequence. Not sure if that is fully warranted for a lazy iteration.

My solution (as a function) right now is:

(fun _ -> 
   lock info (fun _ ->
                info
                |> Seq.iteri (fun i x -> ...)))

I hope it is OK to answer my own question (I am new here).

Moonlight