Я пытаюсь реализовать базовую c программу «стресс-тестирования» в MLton и ее параллельную реализацию ML, в частности, тест Монте-Карло Пи, описанный здесь . Хотя я думаю, что понял большинство из того, что мне нужно, у меня есть проблема в том, что моя программа всегда завершает работу до того, как потоки CML завершат свою работу. Я знаю, что они что-то делают, так как иногда я вижу, как они печатают текст на консоль, которую я должен распечатать, указание, которое я должен был напечатать, но, похоже, между ними начинается гонка, и программа в целом завершается.
Код, с которого я запускаю CML:
local
val iterations : int = 10
val num_threads : int = 1
val still_going : bool ref = ref true
in
val _ = (RunCML.doit ((experiment iterations num_threads still_going), NONE);
(* while !still_going do (); (* Spin-wait for the CML stuff to finish. This doesn't work... *) *)
print "All done!\n")
end
, содержимое функции experiment
:
fun experiment (iterations : int) (num_threads : int) (still_going : bool ref) () : unit = let
val iters_per_thread : int = iterations div num_threads
val return_ivars = Vector.tabulate (num_threads, (fn _ => SyncVar.iVar()))
val _ = Vector.map (fn return_ivar => CML.spawn (montecarlopi iters_per_thread return_ivar)) return_ivars
val return_val = Vector.foldl (fn (elem, acc) => acc + (SyncVar.iGet elem)) 0.0 return_ivars
in
(TextIO.print ("Result is: " ^ (Real.toString return_val) ^ "\n");
still_going := false)
end
и, наконец, функция montecarlopi
:
fun montecarlopi (iterations : int) (return_ivar : real SyncVar.ivar) () = let
val _ = MLton.Random.srand (valOf (MLton.Random.useed ()))
fun helper accumulator 0 = accumulator
| helper accumulator iteration = let
val x : real = wordToBoundedReal (MLton.Random.rand ())
val y : real = wordToBoundedReal (MLton.Random.rand ())
val in_target = (x * x) + (y * y)
val next_iter = iteration - 1
val _ = TextIO.print ("next_iter is: " ^ (Int.toString next_iter) ^ ", in_target is: " ^ (Real.toString in_target) ^ ",x is: " ^ (Real.toString x) ^ ",y is: " ^ (Real.toString y) ^ "\n")
in
if in_target < 1.0 then
helper (accumulator + 1) next_iter
else
helper accumulator next_iter
end
in
SyncVar.iPut (return_ivar, (4.0 * ((real (helper 0 iterations)) / (real iterations))))
end
(Полная (маленькая) программа и сопровождающий ее файл .mlb можно посмотреть здесь ). Я вполне уверен, что биты в вызове функции RunCML.doit
делают то, что они должны, что заставляет меня думать, что проблема заключается в , вероятно , в самой внешней части программы.
Как вы можете видеть, я пытался закрутить ожидание, используя ячейку ref для логического значения, чтобы определить, когда остановиться, но, похоже, это не работает. Также не стоит пытаться раскрутить ожидание, используя RunCML.isRunning
- хотя обе эти идеи звучат как ужасные идеи для начала, на самом деле, в любом случае. Конечно, я не могу использовать что-то вроде канала CML или syncvar, поскольку они должны быть внутри сегмента RunCML.doit
, который будет использоваться. Изменение количества потоков не имеет никакого значения для этой проблемы. Также я не смог найти никаких других функций, которые превратили бы основную часть go в неблокирующее ожидание.
Как заставить внешнюю часть моей программы ждать, пока большая ее часть, внутри вызов функции RunCML.doit
завершен? Или я что-то не так делаю внутри этой части, что вызывает проблему?