src/Pure/Concurrent/synchronized.ML
author wenzelm
Thu, 29 Oct 2009 16:15:33 +0100
changeset 33314 53d49370f7af
parent 33060 e66b41782cb5
child 35015 efafb3337ef3
permissions -rw-r--r--
modernized functor/structures Interpretation;

(*  Title:      Pure/Concurrent/synchronized.ML
    Author:     Fabian Immler and Makarius

State variables with synchronized access.
*)

signature SYNCHRONIZED =
sig
  type 'a var
  val var: string -> 'a -> 'a var
  val value: 'a var -> 'a
  val timed_access: 'a var -> ('a -> Time.time option) -> ('a -> ('b * 'a) option) -> 'b option
  val guarded_access: 'a var -> ('a -> ('b * 'a) option) -> 'b
  val readonly_access: 'a var -> ('a -> 'b option) -> 'b
  val change_result: 'a var -> ('a -> 'b * 'a) -> 'b
  val change: 'a var -> ('a -> 'a) -> unit
  val assign: 'a var -> ('a -> 'a) -> unit
end;

structure Synchronized: SYNCHRONIZED =
struct

(* state variables *)

datatype 'a var = Var of
 {name: string,
  lock: Mutex.mutex,
  cond: ConditionVar.conditionVar,
  var: 'a Unsynchronized.ref};

fun var name x = Var
 {name = name,
  lock = Mutex.mutex (),
  cond = ConditionVar.conditionVar (),
  var = Unsynchronized.ref x};

fun value (Var {var, ...}) = ! var;


(* synchronized access *)

fun access {time_limit, readonly, finish} (Var {name, lock, cond, var}) f =
  SimpleThread.synchronized name lock (fn () =>
    let
      fun try_change () =
        let val x = ! var in
          (case f x of
            NONE =>
              (case Multithreading.sync_wait NONE (time_limit x) cond lock of
                Exn.Result true => try_change ()
              | Exn.Result false => NONE
              | Exn.Exn exn => reraise exn)
          | SOME (y, x') =>
              if readonly then SOME y
              else
                let
                  val _ = magic_immutability_test var
                    andalso raise Fail ("Attempt to change finished variable " ^ quote name);
                  val _ = var := x';
                  val _ = if finish then magic_immutability_mark var else ();
                in SOME y end)
        end;
      val res = try_change ();
      val _ = ConditionVar.broadcast cond;
    in res end);

fun timed_access var time_limit f =
  access {time_limit = time_limit, readonly = false, finish = false} var f;

fun guarded_access var f = the (timed_access var (K NONE) f);

fun readonly_access var f =
  the (access {time_limit = K NONE, readonly = true, finish = false} var
    (fn x => (case f x of NONE => NONE | SOME y => SOME (y, x))));


(* unconditional change *)

fun change_result var f = guarded_access var (SOME o f);
fun change var f = change_result var (fn x => ((), f x));

fun assign var f =
  the (access {time_limit = K NONE, readonly = false, finish = true} var
    (fn x => SOME ((), f x)));

end;