finish removing threads

This commit is contained in:
Simon Cruanes 2023-12-05 13:45:48 -05:00
parent bf2375f042
commit 33053a1f96
No known key found for this signature in database
GPG key ID: EBFFF6F283F3A2B4
10 changed files with 4 additions and 555 deletions

View file

@ -1,4 +1,4 @@
PACKAGES=containers,containers-data,containers-thread PACKAGES=containers,containers-data
all: build test all: build test

View file

@ -39,13 +39,12 @@ Containers is:
data structures that don't have an equivalent in the standard library, data structures that don't have an equivalent in the standard library,
typically not as thoroughly maintained. This is now in its own package typically not as thoroughly maintained. This is now in its own package
since 3.0. since 3.0.
- A separate library for threaded programming in `containers-thread`,
including a blocking queue, semaphores, an extension of `Mutex`, and
thread-pool based futures. This is in its own package since 3.0.
Some of the modules have been moved to their own repository (e.g. `sequence` (now `iter`), Some of the modules have been moved to their own repository (e.g. `sequence` (now `iter`),
`gen`, `qcheck`) and are on opam for great fun and profit. `gen`, `qcheck`) and are on opam for great fun and profit.
Containers-thread has been removed in favor of [Moonpool](https://github.com/c-cube/moonpool/).
## Migration Guide ## Migration Guide
### To 3.0 ### To 3.0
@ -54,7 +53,7 @@ The [changelog's breaking section](CHANGELOG.md) contains a list of the breaking
changes in this release. changes in this release.
1. The biggest change is that some sub-libraries have been either turned into 1. The biggest change is that some sub-libraries have been either turned into
their own packages (`containers-thread`, `containers-data`), their own packages (`containers-data`),
deleted (`containers.iter`),or merged elsewhere (`containers.sexp`). deleted (`containers.iter`),or merged elsewhere (`containers.sexp`).
This means that if use these libraries you will have to edit your This means that if use these libraries you will have to edit your
`dune`/`_oasis`/`opam` files. `dune`/`_oasis`/`opam` files.

View file

@ -1,6 +0,0 @@
(test
(name t)
(flags :standard -strict-sequence -warn-error -a+8)
(modes (best exe))
(package containers-thread)
(libraries containers containers-thread containers_testlib iter threads))

View file

@ -1,9 +0,0 @@
Containers_testlib.run_all ~descr:"containers-thread"
[
T_bq.Test.get ();
T_lock.Test.get ();
T_pool.Test.get ();
T_semaphore.Test.get ();
T_thread.Test.get ();
T_timer.Test.get ();
]

View file

@ -1,64 +0,0 @@
module Test = (val Containers_testlib.make ~__FILE__ ())
open Test
open CCBlockingQueue;;
t @@ fun () ->
let q = create 1 in
let t1 =
CCThread.spawn (fun () ->
push q 1;
push q 2)
in
let t2 =
CCThread.spawn (fun () ->
push q 3;
push q 4)
in
let l = CCLock.create [] in
let t3 =
CCThread.spawn (fun () ->
for _i = 1 to 4 do
let x = take q in
CCLock.update l (fun l -> x :: l)
done)
in
Thread.join t1;
Thread.join t2;
Thread.join t3;
assert_equal [ 1; 2; 3; 4 ] (List.sort Stdlib.compare (CCLock.get l));
true
;;
t @@ fun () ->
let n = 1000 in
let lists =
[|
CCList.(1 -- n); CCList.(n + 1 -- (2 * n)); CCList.((2 * n) + 1 -- (3 * n));
|]
in
let q = create 2 in
let senders =
CCThread.Arr.spawn 3 (fun i ->
if i = 1 then
push_list q lists.(i)
(* test push_list *)
else
List.iter (push q) lists.(i))
in
let res = CCLock.create [] in
let receivers =
CCThread.Arr.spawn 3 (fun i ->
if i = 1 then (
let l = take_list q n in
CCLock.update res (fun acc -> l @ acc)
) else
for _j = 1 to n do
let x = take q in
CCLock.update res (fun acc -> x :: acc)
done)
in
CCThread.Arr.join senders;
CCThread.Arr.join receivers;
let l = CCLock.get res |> List.sort Stdlib.compare in
assert_equal CCList.(1 -- (3 * n)) l;
true

View file

@ -1,101 +0,0 @@
module Test = (val Containers_testlib.make ~__FILE__ ())
open Test
open CCLock;;
t @@ fun () ->
let l = create 0 in
let try_incr l =
update l (fun x ->
Thread.yield ();
x + 1)
in
for _i = 1 to 10 do
ignore (Thread.create try_incr l)
done;
Thread.delay 0.10;
assert_equal 10 (get l);
true
;;
t @@ fun () ->
let l = create 0 in
let test_it l =
with_lock_as_ref l ~f:(fun r ->
(* increment and decrement *)
for j = 0 to 100 do
let x = LockRef.get r in
LockRef.set r (x + 10);
if j mod 5 = 0 then Thread.yield ();
let y = LockRef.get r in
LockRef.set r (y - 10)
done)
in
for _i = 1 to 100 do
ignore (Thread.create test_it l)
done;
Thread.delay 0.10;
0 = get l
;;
t @@ fun () ->
let l = create 5 in
update l (fun x -> x + 1);
get l = 6
;;
t @@ fun () ->
let l = create 5 in
update_map l (fun x -> x + 1, string_of_int x) = "5" && get l = 6
;;
t @@ fun () ->
let l = create 0 in
set l 4;
get l = 4
;;
t @@ fun () ->
let l = create 0 in
set l 4;
set l 5;
get l = 5
;;
t @@ fun () ->
let l = create 0 in
let a = Array.init 100 (fun _ -> Thread.create (fun _ -> incr l) ()) in
Array.iter Thread.join a;
assert_equal ~printer:CCInt.to_string 100 (get l);
true
;;
t @@ fun () ->
let l = create 0 in
incr l;
get l = 1
;;
t @@ fun () ->
let l = create 0 in
decr l;
get l = ~-1
;;
t @@ fun () ->
let l = create 0 in
1 = incr_then_get l && 1 = get l
;;
t @@ fun () ->
let l = create 0 in
0 = get_then_incr l && 1 = get l
;;
t @@ fun () ->
let l = create 10 in
9 = decr_then_get l && 9 = get l
;;
t @@ fun () ->
let l = create 10 in
10 = get_then_decr l && 9 = get l

View file

@ -1,220 +0,0 @@
module Test = (val Containers_testlib.make ~__FILE__ ())
open Test
open CCPool
module P = Make (struct
let max_size = 30
end)
module P2 = Make (struct
let max_size = 15
end)
module Fut = P.Fut
module Fut2 = P2.Fut;;
t @@ fun () ->
List.iter
(fun n ->
let l = Iter.(1 -- n) |> Iter.to_list in
let l =
List.rev_map
(fun _i ->
Fut.make (fun () ->
Thread.delay 0.01;
1))
l
in
let l' = List.map Fut.get l in
assert_equal n (List.fold_left ( + ) 0 l'))
[ 10; 300 ];
true
;;
t @@ fun () ->
List.iter
(fun n ->
let l = Iter.(1 -- n) |> Iter.to_list in
let l =
List.rev_map
(fun _i ->
Fut2.make (fun () ->
Thread.delay 0.01;
1))
l
in
let l' = List.map Fut2.get l in
assert_equal n (List.fold_left ( + ) 0 l'))
[ 10; 300 ];
true
;;
t @@ fun () ->
let a = Fut.make (fun () -> 1) in
let b = Fut.return 42 in
let c = Fut.monoid_product CCPair.make a b in
assert_equal (1, 42) (Fut.get c);
true
;;
t @@ fun () ->
let a = Fut.make (fun () -> 1) in
let b = Fut.make (fun () -> 42) in
let c = Fut.monoid_product CCPair.make a b in
assert_equal (1, 42) (Fut.get c);
true
;;
t @@ fun () ->
let a = Fut.make (fun () -> 1) in
let b = Fut.map succ @@ Fut.make (fun () -> 41) in
let c = Fut.monoid_product CCPair.make a b in
assert_equal (1, 42) (Fut.get c);
true
;;
eq [ 2; 3 ] (Fut.get @@ Fut.map_l (fun x -> Fut.return (x + 1)) [ 1; 2 ]);;
eq [] (Fut.get @@ Fut.map_l (fun x -> Fut.return (x + 1)) []);;
t @@ fun () ->
let l = CCList.(1 -- 50) in
let l' =
l
|> List.map (fun x ->
Fut.make (fun () ->
Thread.delay 0.1;
x * 10))
|> Fut.sequence_l
|> Fut.map (List.fold_left ( + ) 0)
in
let expected = List.fold_left (fun acc x -> acc + (10 * x)) 0 l in
assert_equal expected (Fut.get l');
true
;;
t @@ fun () ->
let l = CCList.(1 -- 100_000) in
let l' =
l
|> CCList.map (fun _x -> Fut.make (fun () -> 1))
|> Fut.sequence_l
|> Fut.map (List.fold_left ( + ) 0)
in
let expected = 100_000 in
assert_equal expected (Fut.get l');
true
;;
t @@ fun () ->
let l = CCList.(1 -- 50) in
let l' =
l
|> List.map (fun x ->
Fut.make (fun () ->
Thread.delay 0.1;
if x = 5 then raise Exit;
x))
|> Fut.sequence_l
|> Fut.map (List.fold_left ( + ) 0)
in
assert_raises (( = ) Exit) (fun () -> Fut.get l');
true
;;
t @@ fun () ->
let rec fib x =
if x < 2 then
1
else
fib (x - 1) + fib (x - 2)
in
let l =
CCList.(1 -- 10_000)
|> List.rev_map (fun x ->
Fut.make (fun () ->
Thread.yield ();
fib (x mod 20)))
|> Fut.(map_l (fun x -> x >|= fun x -> x + 1))
in
assert (Fut.state l = Waiting);
let l' = Fut.get l in
assert_equal 10_000 (List.length l');
true
;;
t @@ fun () ->
let l = CCList.(1 -- 50) in
let l' =
l
|> List.map (fun x ->
Fut2.make (fun () ->
Thread.delay 0.1;
x * 10))
|> Fut2.sequence_l
|> Fut2.map (List.fold_left ( + ) 0)
in
let expected = List.fold_left (fun acc x -> acc + (10 * x)) 0 l in
assert_equal expected (Fut2.get l');
true
;;
t @@ fun () ->
let l = CCList.(1 -- 50) in
let l' =
l
|> List.map (fun x ->
Fut2.make (fun () ->
Thread.delay 0.1;
if x = 5 then raise Exit;
x))
|> Fut2.sequence_l
|> Fut2.map (List.fold_left ( + ) 0)
in
assert_raises (( = ) Exit) (fun () -> Fut2.get l');
true
;;
t @@ fun () ->
let rec fib x =
if x < 2 then
1
else
fib (x - 1) + fib (x - 2)
in
let l =
CCList.(1 -- 10_000)
|> List.rev_map (fun x ->
Fut2.make (fun () ->
Thread.yield ();
fib (x mod 20)))
|> Fut2.(map_l (fun x -> x >|= fun x -> x + 1))
in
assert (Fut2.state l = Waiting);
let l' = Fut2.get l in
assert_equal 10_000 (List.length l');
true
;;
t @@ fun () ->
let start = Unix.gettimeofday () in
let pause = 0.2 and n = 10 in
let l =
CCList.(1 -- n) |> List.map (fun _ -> Fut.make (fun () -> Thread.delay pause))
in
List.iter Fut.get l;
let stop = Unix.gettimeofday () in
assert (stop -. start < float_of_int n *. pause);
true
;;
t @@ fun () ->
let start = Unix.gettimeofday () in
let pause = 0.2 and n = 10 in
let l =
CCList.(1 -- n)
|> List.map (fun _ -> Fut2.make (fun () -> Thread.delay pause))
in
List.iter Fut2.get l;
let stop = Unix.gettimeofday () in
assert (stop -. start < float_of_int n *. pause);
true

View file

@ -1,75 +0,0 @@
module Test = (val Containers_testlib.make ~__FILE__ ())
open Test
open CCSemaphore;;
t @@ fun () ->
let s = create 1 in
let r = CCLock.create false in
let _ =
Thread.create
(fun s ->
acquire 5 s;
CCLock.set r true)
s
in
Thread.yield ();
assert_equal false (CCLock.get r);
release 4 s;
Thread.delay 0.2;
assert_equal true (CCLock.get r);
assert_equal 0 (get s);
true
;;
t @@ fun () ->
let s = create 5 in
let n = CCLock.create 0 in
let a =
Array.init 100 (fun i ->
Thread.create
(fun _ ->
for _i = 1 to 100 do
with_acquire
~n:(1 + (i mod 5))
s
~f:(fun () ->
Thread.yield ();
CCLock.incr n)
done)
())
in
Array.iter Thread.join a;
assert_equal ~printer:CCInt.to_string 5 (get s);
assert_equal ~printer:CCInt.to_string 10_000 (CCLock.get n);
true
;;
t @@ fun () ->
let output _s = () in
let s = create 2 in
let res = CCLock.create false in
let id =
Thread.create
(fun () ->
output "start";
wait_until_at_least ~n:5 s ~f:(fun () ->
assert (get s >= 5);
output "modify now";
CCLock.set res true))
()
in
output "launched thread";
Thread.yield ();
assert (not (CCLock.get res));
output "release 2";
release 2 s;
Thread.yield ();
assert (not (CCLock.get res));
output "release 1";
release 1 s;
(* should work now *)
Thread.delay 0.2;
Thread.join id;
output "check";
assert (CCLock.get res);
true

View file

@ -1,32 +0,0 @@
module Test = (val Containers_testlib.make ~__FILE__ ())
open Test
open CCThread;;
t @@ fun () ->
let l = CCLock.create 0 in
let a = Arr.spawn 101 (fun i -> CCLock.update l (( + ) i)) in
Arr.join a;
let n = Iter.(1 -- 100 |> fold ( + ) 0) in
assert_equal ~printer:CCInt.to_string n (CCLock.get l);
true
;;
t @@ fun () ->
let b = Barrier.create () in
let res = CCLock.create 0 in
let t1 =
spawn (fun _ ->
Barrier.wait b;
CCLock.incr res)
and t2 =
spawn (fun _ ->
Barrier.wait b;
CCLock.incr res)
in
Thread.delay 0.2;
assert_equal 0 (CCLock.get res);
Barrier.activate b;
Thread.join t1;
Thread.join t2;
assert_equal 2 (CCLock.get res);
true

View file

@ -1,43 +0,0 @@
module Test = (val Containers_testlib.make ~__FILE__ ())
open Test
open CCTimer;;
(* NOTE: could be tighter bounds, but travis' mac OS seems to be dog slow. *)
t @@ fun () ->
let start = Unix.gettimeofday () in
let timer = create () in
let res = CCLock.create 0 in
let sem = CCSemaphore.create 1 in
CCSemaphore.acquire 1 sem;
let stop = ref 0. in
every timer 0.1 ~f:(fun () ->
if CCLock.incr_then_get res > 5 then (
stop := Unix.gettimeofday ();
CCSemaphore.release 1 sem;
raise ExitEvery
));
CCSemaphore.acquire 1 sem;
(* wait *)
assert_equal ~printer:CCInt.to_string 6 (CCLock.get res);
assert (!stop -. start >= 0.49999);
assert (!stop -. start < 2.);
true
;;
t @@ fun () ->
(* scenario: n := 1; n := n*4 ; n := n+2; res := n *)
let timer = create () in
let n = CCLock.create 1 in
let res = CCLock.create 0 in
after timer 0.3 ~f:(fun () -> CCLock.update n (fun x -> x + 2));
ignore
(Thread.create
(fun _ ->
Thread.delay 0.4;
CCLock.set res (CCLock.get n))
());
after timer 0.1 ~f:(fun () -> CCLock.update n (fun x -> x * 4));
Thread.delay 0.6;
assert_equal ~printer:Q.Print.int 6 (CCLock.get res);
true