feat(jobs): real OS threads - Job.parallel_for, fn name, thread-safe Sync
- `fn name` names a top-level function as a value (E_FNREF, lowers to @fn_<name>); the worker entry point for Job.parallel_for, which checks it takes (int, pointer-like) and returns void. - runtime/native/threads.ll (pthreads) and threads_win.ll (Win32 SRWLOCK/CONDITION_VARIABLE): a pool of one worker per core but one, parked between batches; every thread claims chunks by compare-and-swap. Linked only into programs that use Job/Promise/Sync, by `ludicc -o`, `ludic build` and the test suite's build helper. - Sync.* is real: native mutexes, atomics as cmpxchg retry loops (neither clang takes atomicrw, the PC's rejects seq_consistent), mutex-guarded channels, Sync.cpu_count from the OS. - spawn/despawn on a pool thread stop the program with a located panic. - examples/library/threads.ludic and its test; docs for fn, Job.parallel_for, Job.is_worker. - Reseeded (bootstrap-cfree: out.ll == seed.ll). 141/141 on macOS; jobs, threads and the guard pass on Windows from the reseeded Windows seed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
f5d1a62ccf
commit
c10abd9f9f
22 changed files with 57464 additions and 55794 deletions
34
docs/language/job/job-parallel_for.md
Normal file
34
docs/language/job/job-parallel_for.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
id: job-parallel_for
|
||||
name: Job.parallel_for
|
||||
category: job
|
||||
kind: namespace-method
|
||||
tokens: Job.parallel_for
|
||||
sig: Job.parallel_for(count, work, ctx) -> void
|
||||
tip: Run work(i, ctx) for every i in [0, count) across all cores; returns when every call is done.
|
||||
order: 16
|
||||
ns: Job
|
||||
member: parallel_for
|
||||
---
|
||||
|
||||
Run `work(i, ctx)` for every `i` in `[0, count)` on real OS threads, and return when every call has
|
||||
finished. The indices are split into chunks shared by a worker pool (one thread per core but one,
|
||||
started on first use) and the calling thread, so each index runs exactly once, in no particular order.
|
||||
|
||||
`work` is a top-level function taking `(i: int, ctx)`, named with `fn`; `ctx` is whatever it computes
|
||||
on (`words`, `bytes` or a `pointer`). A worker computes on what it was handed and writes only its own
|
||||
index's results: it must not `spawn`, `despawn`, `push` onto a list another thread can see, or use
|
||||
Http or Audio. `spawn` and `despawn` on a worker stop the program with a located message. Shared
|
||||
counters go through `Sync.add`, shared totals behind a `Sync.mutex`.
|
||||
|
||||
```ludic
|
||||
program Squares {
|
||||
function square(i: int, out: words) -> void { out[i] = i * i }
|
||||
|
||||
entry {
|
||||
let sq = words(20000)
|
||||
Job.parallel_for(20000, fn square, sq)
|
||||
print(sq[141])
|
||||
}
|
||||
}
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue