ludic/docs/language/job/job-parallel_for.md
Orkuncakilkaya c10abd9f9f 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>
2026-09-15 13:52:22 +03:00

1.2 KiB

id name category kind tokens sig tip order ns member
job-parallel_for Job.parallel_for job namespace-method Job.parallel_for Job.parallel_for(count, work, ctx) -> void Run work(i, ctx) for every i in [0, count) across all cores; returns when every call is done. 16 Job 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.

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])
  }
}