第二十章:线程
级别 3 -- 经验
使用 C 线程、互斥量和条件变量进行共享内存并发——以及为什么 Auto 的 Actor 模型使大部分这些变得不必要。
并发是 C 程序最容易出错的地方。数据竞争、死锁和微妙的内存排序错误以难以复现和修复而闻名。C11 引入了基于 POSIX 线程的标准线程 API。Auto 采取了根本不同的方法:具有隔离状态的 Actor 通过消息传递进行通信。
20.1 简单的线程间控制
C11 提供了 thrd_create 和 thrd_join 用于线程管理:
c
// C 深入:线程创建
#include <threads.h>
#include <stdio.h>
int worker(void *arg) {
int id = *(int *)arg;
printf("Worker %d started\n", id);
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}
printf("Worker %d finished, sum = %d\n", id, sum);
return 0;
}
int main(void) {
thrd_t t1, t2;
int id1 = 1, id2 = 2;
thrd_create(&t1, worker, &id1);
thrd_create(&t2, worker, &id2);
thrd_join(t1, NULL);
thrd_join(t2, NULL);
return 0;
}C 深入: C 线程共享整个地址空间。每个线程都可以读写每个全局变量。这使得数据竞争极其容易创建。线程函数必须返回
int(不是 POSIX 的void*)。thrd_create的参数以void*传递——这是类型错误的常见来源。
Auto 的方法。 Auto 使用 Actor 模型代替原始线程:
auto
// Auto:顺序执行(Actor 模型计划中)
fn worker(id int) {
print("Worker", id, "started")
var sum int = 0
for i in 0..100 {
sum = sum + i
}
print("Worker", id, "finished, sum =", sum)
}
fn main() {
worker(1)
worker(2)
}