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