# thread

> Concurrency primitives in Langoost — goroutines, worker pools, async futures, channels, mutexes, RW locks, semaphores, atomics, and a scheduler.

# thread

The `thread` module provides Langoost's concurrency primitives. It is VM-based:
each spawned function runs in its own isolated VM with a copy of the current
globals, so tasks don't share mutable state unless you opt in via
[`runtime.core`](/docs/stdlib/runtime). Import it with `import thread`.

Most primitives are handle-based — `new` returns an integer id you pass to the
other calls, and `free` releases it. For a tutorial-style introduction with
examples, see the **[concurrency guide](/docs/concurrency)**.

## thread.core

| Function | Signature | Description |
| --- | --- | --- |
| `spawn` | `thread.core.spawn(fn)` | Run `fn` in a new goroutine |
| `sleep` | `thread.core.sleep(ms: int)` | Sleep the current task |
| `cpus` | `thread.core.cpus() → int` | Number of CPU cores |
| `goroutines` | `thread.core.goroutines() → int` | Live goroutine count |

## thread.pool

| Function | Signature | Description |
| --- | --- | --- |
| `new` | `thread.pool.new(workers: int) → int` | Create a worker pool |
| `submit` | `thread.pool.submit(id: int, fn) → bool` | Queue a task |
| `wait` | `thread.pool.wait(id: int)` | Block until all tasks finish |
| `free` | `thread.pool.free(id: int)` | Release the pool |

## thread.async

| Function | Signature | Description |
| --- | --- | --- |
| `run` | `thread.async.run(fn) → int` | Run `fn` asynchronously; returns a future id |
| `await` | `thread.async.await(id: int) → string` | Block for the result |
| `isDone` | `thread.async.isDone(id: int) → bool` | Whether the future has completed |
| `free` | `thread.async.free(id: int)` | Release the future |

## thread.mutex

| Function | Signature | Description |
| --- | --- | --- |
| `new` | `thread.mutex.new() → int` | Create a mutex |
| `lock` | `thread.mutex.lock(id: int)` | Acquire (blocks) |
| `unlock` | `thread.mutex.unlock(id: int)` | Release |
| `tryLock` | `thread.mutex.tryLock(id: int) → bool` | Non-blocking acquire |
| `free` | `thread.mutex.free(id: int)` | Release the mutex |

## thread.rwlock

| Function | Signature | Description |
| --- | --- | --- |
| `new` | `thread.rwlock.new() → int` | Create a reader/writer lock |
| `rlock` | `thread.rwlock.rlock(id: int)` | Acquire a read lock (multiple readers) |
| `runlock` | `thread.rwlock.runlock(id: int)` | Release a read lock |
| `lock` | `thread.rwlock.lock(id: int)` | Acquire the write lock (exclusive) |
| `unlock` | `thread.rwlock.unlock(id: int)` | Release the write lock |
| `free` | `thread.rwlock.free(id: int)` | Release the lock |

## thread.channel

| Function | Signature | Description |
| --- | --- | --- |
| `new` | `thread.channel.new(capacity?: int) → int` | Create a channel (unbuffered by default) |
| `send` | `thread.channel.send(id: int, value: string) → bool` | Send a value |
| `recv` | `thread.channel.recv(id: int) → string` | Receive (blocks; `""` when closed) |
| `recvTimeout` | `thread.channel.recvTimeout(id: int, ms: int) → string` | Receive with a timeout |
| `close` | `thread.channel.close(id: int)` | Close the channel |
| `len` | `thread.channel.len(id: int) → int` | Buffered item count |
| `cap` | `thread.channel.cap(id: int) → int` | Capacity |

## thread.semaphore

| Function | Signature | Description |
| --- | --- | --- |
| `new` | `thread.semaphore.new(n: int) → int` | Create a semaphore with `n` permits |
| `acquire` | `thread.semaphore.acquire(id: int)` | Take a permit (blocks) |
| `release` | `thread.semaphore.release(id: int)` | Return a permit |
| `tryAcquire` | `thread.semaphore.tryAcquire(id: int) → bool` | Non-blocking acquire |
| `free` | `thread.semaphore.free(id: int)` | Release the semaphore |

## thread.atomic

| Function | Signature | Description |
| --- | --- | --- |
| `new` | `thread.atomic.new(initial?: int) → int` | Create an atomic integer |
| `load` | `thread.atomic.load(id: int) → int` | Read the value |
| `store` | `thread.atomic.store(id: int, n: int)` | Write the value |
| `add` | `thread.atomic.add(id: int, n: int) → int` | Add and return the new value |
| `swap` | `thread.atomic.swap(id: int, n: int) → int` | Set and return the old value |
| `cas` | `thread.atomic.cas(id: int, old: int, new: int) → bool` | Compare-and-swap |
| `free` | `thread.atomic.free(id: int)` | Release the atomic |

## thread.scheduler

| Function | Signature | Description |
| --- | --- | --- |
| `new` | `thread.scheduler.new() → int` | Create a scheduler |
| `add` | `thread.scheduler.add(id: int, fn) → bool` | Queue a function |
| `run` | `thread.scheduler.run(id: int)` | Run all queued functions in order |
| `size` | `thread.scheduler.size(id: int) → int` | Number of queued functions |
| `free` | `thread.scheduler.free(id: int)` | Release the scheduler |

## Example

```goost
import thread

let mu = thread.mutex.new()
let counter = thread.atomic.new(0)

fn worker() {
    thread.mutex.lock(mu)
    thread.atomic.add(counter, 1)
    thread.mutex.unlock(mu)
}

let pool = thread.pool.new(4)
let i = 0
while i < 100 {
    thread.pool.submit(pool, worker)
    i += 1
}
thread.pool.wait(pool)

println(thread.atomic.load(counter))   // 100
```