src/Pure/Concurrent/multithreading.ML
author wenzelm
Sat Apr 02 23:29:05 2016 +0200 (2016-04-02 ago)
changeset 62826 eb94e570c1a4
parent 62715 8312e5d8d217
child 62891 7a11ea5c9626
permissions -rw-r--r--
prefer infix operations;
     1 (*  Title:      Pure/Concurrent/multithreading.ML
     2     Author:     Makarius
     3 
     4 Multithreading in Poly/ML (cf. polyml/basis/Thread.sml).
     5 *)
     6 
     7 signature BASIC_MULTITHREADING =
     8 sig
     9   val interruptible: ('a -> 'b) -> 'a -> 'b
    10   val uninterruptible: ((('c -> 'd) -> 'c -> 'd) -> 'a -> 'b) -> 'a -> 'b
    11 end;
    12 
    13 signature MULTITHREADING =
    14 sig
    15   include BASIC_MULTITHREADING
    16   val no_interrupts: Thread.threadAttribute list
    17   val public_interrupts: Thread.threadAttribute list
    18   val private_interrupts: Thread.threadAttribute list
    19   val sync_interrupts: Thread.threadAttribute list -> Thread.threadAttribute list
    20   val interrupted: unit -> unit  (*exception Interrupt*)
    21   val with_attributes: Thread.threadAttribute list -> (Thread.threadAttribute list -> 'a) -> 'a
    22   val max_threads_value: unit -> int
    23   val max_threads_update: int -> unit
    24   val enabled: unit -> bool
    25   val sync_wait: Thread.threadAttribute list option -> Time.time option ->
    26     ConditionVar.conditionVar -> Mutex.mutex -> bool Exn.result
    27   val trace: int ref
    28   val tracing: int -> (unit -> string) -> unit
    29   val tracing_time: bool -> Time.time -> (unit -> string) -> unit
    30   val real_time: ('a -> unit) -> 'a -> Time.time
    31   val synchronized: string -> Mutex.mutex -> (unit -> 'a) -> 'a
    32   val serial: unit -> int
    33 end;
    34 
    35 structure Multithreading: MULTITHREADING =
    36 struct
    37 
    38 (* thread attributes *)
    39 
    40 val no_interrupts =
    41   [Thread.EnableBroadcastInterrupt false, Thread.InterruptState Thread.InterruptDefer];
    42 
    43 val test_interrupts =
    44   [Thread.EnableBroadcastInterrupt false, Thread.InterruptState Thread.InterruptSynch];
    45 
    46 val public_interrupts =
    47   [Thread.EnableBroadcastInterrupt true, Thread.InterruptState Thread.InterruptAsynchOnce];
    48 
    49 val private_interrupts =
    50   [Thread.EnableBroadcastInterrupt false, Thread.InterruptState Thread.InterruptAsynchOnce];
    51 
    52 val sync_interrupts = map
    53   (fn x as Thread.InterruptState Thread.InterruptDefer => x
    54     | Thread.InterruptState _ => Thread.InterruptState Thread.InterruptSynch
    55     | x => x);
    56 
    57 val safe_interrupts = map
    58   (fn Thread.InterruptState Thread.InterruptAsynch =>
    59       Thread.InterruptState Thread.InterruptAsynchOnce
    60     | x => x);
    61 
    62 fun interrupted () =
    63   let
    64     val orig_atts = safe_interrupts (Thread.getAttributes ());
    65     val _ = Thread.setAttributes test_interrupts;
    66     val test = Exn.capture Thread.testInterrupt ();
    67     val _ = Thread.setAttributes orig_atts;
    68   in Exn.release test end;
    69 
    70 fun with_attributes new_atts e =
    71   let
    72     val orig_atts = safe_interrupts (Thread.getAttributes ());
    73     val result = Exn.capture (fn () =>
    74       (Thread.setAttributes (safe_interrupts new_atts); e orig_atts)) ();
    75     val _ = Thread.setAttributes orig_atts;
    76   in Exn.release result end;
    77 
    78 
    79 (* portable wrappers *)
    80 
    81 fun interruptible f x = with_attributes public_interrupts (fn _ => f x);
    82 
    83 fun uninterruptible f x =
    84   with_attributes no_interrupts (fn atts =>
    85     f (fn g => fn y => with_attributes atts (fn _ => g y)) x);
    86 
    87 
    88 (* options *)
    89 
    90 fun num_processors () =
    91   (case Thread.numPhysicalProcessors () of
    92     SOME n => n
    93   | NONE => Thread.numProcessors ());
    94 
    95 fun max_threads_result m =
    96   if m > 0 then m else Int.min (Int.max (num_processors (), 1), 8);
    97 
    98 val max_threads = ref 1;
    99 fun max_threads_value () = ! max_threads;
   100 fun max_threads_update m = max_threads := max_threads_result m;
   101 
   102 fun enabled () = max_threads_value () > 1;
   103 
   104 
   105 (* synchronous wait *)
   106 
   107 fun sync_wait opt_atts time cond lock =
   108   with_attributes
   109     (sync_interrupts (case opt_atts of SOME atts => atts | NONE => Thread.getAttributes ()))
   110     (fn _ =>
   111       (case time of
   112         SOME t => Exn.Res (ConditionVar.waitUntil (cond, lock, t))
   113       | NONE => (ConditionVar.wait (cond, lock); Exn.Res true))
   114       handle exn => Exn.Exn exn);
   115 
   116 
   117 (* tracing *)
   118 
   119 val trace = ref 0;
   120 
   121 fun tracing level msg =
   122   if level > ! trace then ()
   123   else uninterruptible (fn _ => fn () =>
   124     (TextIO.output (TextIO.stdErr, (">>> " ^ msg () ^ "\n")); TextIO.flushOut TextIO.stdErr)
   125       handle _ (*sic*) => ()) ();
   126 
   127 fun tracing_time detailed time =
   128   tracing
   129    (if not detailed then 5
   130     else if time >= seconds 1.0 then 1
   131     else if time >= seconds 0.1 then 2
   132     else if time >= seconds 0.01 then 3
   133     else if time >= seconds 0.001 then 4 else 5);
   134 
   135 fun real_time f x =
   136   let
   137     val timer = Timer.startRealTimer ();
   138     val () = f x;
   139     val time = Timer.checkRealTimer timer;
   140   in time end;
   141 
   142 
   143 (* synchronized evaluation *)
   144 
   145 fun synchronized name lock e =
   146   Exn.release (uninterruptible (fn restore_attributes => fn () =>
   147     let
   148       val immediate =
   149         if Mutex.trylock lock then true
   150         else
   151           let
   152             val _ = tracing 5 (fn () => name ^ ": locking ...");
   153             val time = real_time Mutex.lock lock;
   154             val _ = tracing_time true time (fn () => name ^ ": locked after " ^ Time.toString time);
   155           in false end;
   156       val result = Exn.capture (restore_attributes e) ();
   157       val _ = if immediate then () else tracing 5 (fn () => name ^ ": unlocking ...");
   158       val _ = Mutex.unlock lock;
   159     in result end) ());
   160 
   161 
   162 (* serial numbers *)
   163 
   164 local
   165 
   166 val serial_lock = Mutex.mutex ();
   167 val serial_count = ref 0;
   168 
   169 in
   170 
   171 val serial = uninterruptible (fn _ => fn () =>
   172   let
   173     val _ = Mutex.lock serial_lock;
   174     val _ = serial_count := ! serial_count + 1;
   175     val res = ! serial_count;
   176     val _ = Mutex.unlock serial_lock;
   177   in res end);
   178 
   179 end;
   180 
   181 end;
   182 
   183 structure Basic_Multithreading: BASIC_MULTITHREADING = Multithreading;
   184 open Basic_Multithreading;