From 108719207c81b85360ca63eebbf64ab7cdee60e2 Mon Sep 17 00:00:00 2001 From: muqiuhan Date: Tue, 15 Aug 2023 05:30:55 +0000 Subject: deploy: c5a7c0e217a91c05e60b492bc0e944ce73531c17 --- .../index.html | 225 ++++++++++++++++++++ .../08/15/poll-error-attribute-in-OCaml/index.html | 232 +++++++++++++++++++++ .../index.html" | 224 ++++++++++++++++++++ 3 files changed, 681 insertions(+) create mode 100644 2023/08/15/Typed-Design-Patterns-for-the-Functional-Era/index.html create mode 100644 2023/08/15/poll-error-attribute-in-OCaml/index.html create mode 100644 "2023/08/15/tick-thread\345\234\250Multicore-OCaml\344\270\255\347\232\204\344\275\234\347\224\250/index.html" (limited to '2023/08/15') diff --git a/2023/08/15/Typed-Design-Patterns-for-the-Functional-Era/index.html b/2023/08/15/Typed-Design-Patterns-for-the-Functional-Era/index.html new file mode 100644 index 00000000..f8939841 --- /dev/null +++ b/2023/08/15/Typed-Design-Patterns-for-the-Functional-Era/index.html @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + + + + + +Typed Design Patterns for the Functional Era | 暮秋小屋 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+
+ + + +
+
+
+ + +
+
+
+ + +
+ +
+ +
+ +
+
+
+ +
+ + + + + +
+ + + + + + + +
+ + +
+
+
+ + + +
+ + + + + + diff --git a/2023/08/15/poll-error-attribute-in-OCaml/index.html b/2023/08/15/poll-error-attribute-in-OCaml/index.html new file mode 100644 index 00000000..0cc7776a --- /dev/null +++ b/2023/08/15/poll-error-attribute-in-OCaml/index.html @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + +使用 [@poll error] 实现线程安全的数据结构 | 暮秋小屋 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+
+ + + +
+
+
+ + +
+
+
+ + +
+ +
+ +
+ +
+
+
+

OCaml的标准库提供了许多mutable的数据结构,比如Hashtbl, Queue, Stack之类的,但是这些数据结构都不是线程安全的。在 OCaml 4 和 OCaml 5 中,单个Domain中一次只能运行一个线程。换句话说,单个Domain中的线程仍然不会并行运行,除非在不同所的Domain中。

+

而在单个Domain中 OCaml 的 runtime 是通过在safe point期间半抢占式的切换线程。也就是说,线程切换只会发生在safe point期间。例如内存分配就是是safe point。这意味着在没有safe point的代码块内,可以在Domain内原子性地进行多次读写或访问操作,因为线程没被切换。

+

OCaml 编译器提供了一个名为 [@poll error] 的annotation,可以在函数中使用它来确保该函数不包含safe point。

+

所以通过使用 [@poll error] 就可以创建在Domain内原子性执行的函数,也就是说,基于此特性可以实现单个Domain内线程安全的数据结构,例如 thread-table 便是使用这个特性实现的 Hash Table。可以看看它的 add 函数的实现:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let[@poll error] add_atomically t buckets n i before after =
t.rehash = 0 && buckets == t.buckets
&& before == Array.unsafe_get buckets i
&& begin
Array.unsafe_set buckets i after;
let length = t.length + 1 in
t.length <- length;
if n < length && n < max_buckets_div_2 then t.rehash <- n * 2;
true
end

let rec add t k' v' =
let h = Mix.int k' in
maybe_rehash t;
let buckets = t.buckets in
let n = Array.length buckets in
let i = h land (n - 1) in
let before = Array.unsafe_get buckets i in
let after = Cons (k', v', before) in
if not (add_atomically t buckets n i before after) then add t k' v'
+ +

相比使用 Stdlib.Mutex,这种无锁实现会有更好的性能(特别是对于只读操作),并且还允许例如信号处理之类的上下文操作。

+ +
+ + + + + +
+ + + + + + + +
+ + +
+
+
+ + + +
+ + + + + + diff --git "a/2023/08/15/tick-thread\345\234\250Multicore-OCaml\344\270\255\347\232\204\344\275\234\347\224\250/index.html" "b/2023/08/15/tick-thread\345\234\250Multicore-OCaml\344\270\255\347\232\204\344\275\234\347\224\250/index.html" new file mode 100644 index 00000000..de11afdd --- /dev/null +++ "b/2023/08/15/tick-thread\345\234\250Multicore-OCaml\344\270\255\347\232\204\344\275\234\347\224\250/index.html" @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + +tick thread在Multicore OCaml中的作用 | 暮秋小屋 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+
+ + + +
+
+
+ + +
+
+
+ + +
+ +
+ +
+ +
+
+
+

Multicore OCaml的程序在启动时会运行一个 tick thread,其实现如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* The tick thread: posts a SIGPREEMPTION signal periodically */

static void * caml_thread_tick(void * arg)
{
struct timeval timeout;
sigset_t mask;

/* Block all signals so that we don't try to execute an OCaml signal handler*/
sigfillset(&mask);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
while(! caml_tick_thread_stop) {
/* select() seems to be the most efficient way to suspend the
thread for sub-second intervals */
timeout.tv_sec = 0;
timeout.tv_usec = Thread_timeout * 1000;
select(0, NULL, NULL, NULL, &timeout);
/* The preemption signal should never cause a callback, so don't
go through caml_handle_signal(), just record signal delivery via
caml_record_signal(). */
caml_record_signal(SIGPREEMPTION);
}
return NULL;
}
+ +

这是因为Multicore OCaml的GC目前需要一个进程(或一个Domain)中的所有线程一起参与以避免并发访问。如果一个线程在system call上被阻塞,那么整个Domain就会被卡住,直到该线程可以参与当前的垃圾收集。为了避免这个问题,tick 线程可以代替被阻塞的线程执行垃圾收集操作。

+ +
+ + + + + +
+ + + + + + + +
+ + +
+
+
+ + + +
+ + + + + + -- cgit v1.2.3