Backend
zig-concurrency
Zig 并发编程技能。涉及 std.Thread 的线程创建、同步原语(Mutex、RwLock、Condition、Semaphore、WaitGroup)、线程池和原子操作。在需要多线程或并行计算时调用。
Zig 并发编程技能。涉及 std.Thread 的线程创建、同步原语(Mutex、RwLock、Condition、Semaphore、WaitGroup)、线程池和原子操作。在需要多线程或并行计算时调用。
基于 std.Thread 和 std.atomic 的并发原语(Zig 0.16.0)。
zig version)zig-http 或 zig-0.16 的 std.Iozig-0.16 技能本技能不收集、存储或传输任何用户数据。
步骤 1. 识别并发需求 — CPU 密集 / I/O 等待 / 并行计算? 步骤 2. 选择原语 — 线程 / 线程池 / 原子操作? 步骤 3. 实现同步 — Mutex / RwLock / WaitGroup 步骤 4. 测试正确性 — 竞态条件、死锁检查
std.Thread // 线程创建与管理
std.Thread.Mutex // 互斥锁
std.Thread.Mutex.Recursive // 可重入互斥锁
std.Thread.RwLock // 读写锁
std.Thread.Condition // 条件变量
std.Thread.Semaphore // 计数信号量
std.Thread.ResetEvent // 布尔事件标志(阻塞式)
std.Thread.WaitGroup // 等待多任务完成
std.Thread.Pool // 线程池
std.Thread.Futex // 底层 futex(高级)
std.atomic.Value(T) // 原子类型包装
fn worker(id: usize) void {
std.debug.print("Worker {d}\n", .{id});
}
const thread = try std.Thread.spawn(.{}, worker, .{42});
thread.join(); // 等待完成
const thread = try std.Thread.spawn(.{ .allocator = allocator }, worker, .{42});
defer thread.join();
const thread = try std.Thread.spawn(.{}, worker, .{1});
thread.detach(); // 线程自动清理
var mutex: std.Thread.Mutex = .{};
var shared: i32 = 0;
fn increment() void {
mutex.lock();
defer mutex.unlock();
shared += 1;
}
var rwlock: std.Thread.RwLock = .{};
var data: i32 = 0;
fn reader() void {
rwlock.lockShared();
defer rwlock.unlockShared();
_ = data; // 可并发读
}
fn writer() void {
rwlock.lock();
defer rwlock.unlock();
data += 1; // 独占写
}
var mutex: std.Thread.Mutex = .{};
var cond: std.Thread.Condition = .{};
var ready: bool = false;
fn waiter() void {
mutex.lock();
defer mutex.unlock();
while (!ready) {
cond.wait(&mutex); // 等待通知
}
}
fn notifier() void {
mutex.lock();
defer mutex.unlock();
ready = true;
cond.signal(); // 或 cond.broadcast() 通知所有等待者
}
var sem = std.Thread.Semaphore{ .permits = 3 }; // 最多 3 个并发
fn worker() void {
sem.wait(); // 获取许可
defer sem.post(); // 释放许可
// 执行工作...
}
var wg: std.Thread.WaitGroup = .{};
wg.reset(); // 初始化计数器为 0
fn worker(wg: *std.Thread.WaitGroup) void {
defer wg.finish();
// 执行工作
}
// 启动 5 个任务
wg.start(); // +1
const t1 = try std.Thread.spawn(.{}, worker, .{&wg});
wg.start(); // +1
const t2 = try std.Thread.spawn(.{}, worker, .{&wg});
wg.wait(); // 等待所有 finish()
var event: std.Thread.ResetEvent = .{};
fn waiter() void {
event.wait(); // 阻塞直到被设置
}
fn setter() void {
// ... 准备工作
event.set(); // 通知等待者
}
var pool: std.Thread.Pool = .{};
try pool.init(.{ .max_threads = 4 });
defer pool.deinit();
// 提交任务
for (0..100) |i| {
try pool.spawn(worker, .{i});
}
// pool.deinit() 等待所有任务完成
var counter: std.atomic.Value(u64) = .{ .raw = 0 };
// 原子递增
_ = counter.fetchAdd(1, .acq_rel);
// 原子加载/存储
const val = counter.load(.acquire);
counter.store(42, .release);
// CAS(比较并交换)
const prev = counter.cmpxchgWeak(42, 100, .acq_rel, .acquire);
// 从弱到强
.monotonic // 仅保证原子性,无同步语义
.acquire // 读取后所有后续操作可见
.release // 写入前所有操作已完成
.acq_rel // acquire + release
.seq_cst // 全局顺序一致(默认)
const Queue = struct {
items: std.ArrayList(i32),
mutex: std.Thread.Mutex = .{},
cond: std.Thread.Condition = .{},
done: bool = false,
};
fn producer(q: *Queue) void {
for (0..10) |i| {
q.mutex.lock();
q.items.append(@intCast(i));
q.cond.signal();
q.mutex.unlock();
}
q.mutex.lock();
q.done = true;
q.cond.broadcast();
q.mutex.unlock();
}
fn consumer(q: *Queue) void {
q.mutex.lock();
while (!q.done or q.items.items.len > 0) {
while (q.items.items.len == 0 and !q.done)
q.cond.wait(&q.mutex);
if (q.items.popOrNull()) |item| { /* 处理 */ }
}
q.mutex.unlock();
}
fn(Args) void,结果通过共享内存传递*std.Thread.Mutexcond.wait() 返回后必须重新检查条件(用 while 而非 if)pool.spawn 可能阻塞 — 线程池满时 spawn 会等待空闲线程std.Thread.spawn 的配置参数 — 第一个参数是 .{}(默认配置),可设置 stack_size 等defer 是解锁的最佳实践 — mutex.lock() 后立即 defer mutex.unlock() 防止遗漏Q:什么时候用 Mutex vs RwLock? A:读多写少用 RwLock(读者可并发),读写比例接近或用 Mutex(实现简单,无锁竞争开销)。
Q:线程池大小怎么设置?
A:CPU 密集型用 std.Thread.getCpuCount() 或手动设为核数;I/O 密集型可以设更大(如 4×核数)。
Q:std.Thread.spawn 和 pool.spawn 区别?
A:前者创建独立线程,适合少量长期任务;后者交给线程池复用线程,适合大量短任务。