let map_parallel (func : 'a -> 'b) (items : 'a[]) =
let results = Array.zero_create (items.Length)
let count = ref items.Length
use notify = new System.Threading.AutoResetEvent(false)
items
|> Array.iteri (
fun i item ->
System.Threading.ThreadPool.QueueUserWorkItem (
fun _ ->
let res = func item
results.[i] <- res
!: System.Threading.Interlocked.Decrement count |> ignore
!: if !count = 0 then notify.Set() |> ignore
) |> ignore
)
notify.WaitOne() |> ignore
results
I have marked the two faulty lines in the code above with "!:". The (hopefully) correct version is:
let c = System.Threading.Interlocked.Decrement count
if c = 0 then notify.Set() |> ignore
In the faulty version, it is possible for two threads to execute "then notify.Set()". The second thread may then raise an exception as "notify" may already have been disposed of.
The code in the original post was corrected.