pthread.js is a pthread-inspired JavaScript library for Node.js and browsers. It exposes pthread-style names, selects the strongest runtime available, and downscales when shared memory is missing or blocked.
Runtime selection is automatic:
shared-memory:SharedArrayBufferplus blockingAtomics.message-worker: Web Workers or Node.jsworker_threadswithout shared memory.promise: same-event-loop scheduling for restricted runtimes.
Fallback runtimes cannot exactly reproduce native blocking semantics. In those modes, operations that would block in C can return a Promise<number>.
- Install
- JavaScript Usage
- Worker Usage
- Web Usage
- C pthread vs pthread.js
- API Coverage
- Minimum Runtime Versions
- License
npm install pthread.jsimportThreadfrom'pthread.js';constthread=newThread();awaitthread.pthread_create(asyncvalue=>{returnvalue*2;},21);console.log(awaitthread.pthread_join());importThreadfrom'pthread.js';constthread=newThread();awaitthread.pthread_create(newURL('./worker.mjs',import.meta.url),{left: 2,right: 3});console.log(awaitthread.pthread_join());import{pthread_worker_main}from'pthread.js/worker';pthread_worker_main(asyncarg=>{returnarg.left+arg.right;});Use pthread.js directly from jsDelivr with one <script> tag:
<buttonid="run">Run</button><outputid="result"></output><scripttype="module">importThread,{detectRuntime}from'https://cdn.jsdelivr.net/npm/pthread.js@0.2.5/index.js';constbutton=document.querySelector('#run');constresult=document.querySelector('#result');button.addEventListener('click',async()=>{constthread=newThread();awaitthread.pthread_create(asyncname=>`hello ${name}`,'browser');result.textContent=awaitthread.pthread_join();console.table(detectRuntime());});</script>The browser automatically downscales. If SharedArrayBuffer and blocking Atomics are available, pthread.js uses the shared-memory backend. If not, it uses Web Workers. If workers are not available, it uses the promise backend.
To enable the strongest browser backend, serve your app with cross-origin isolation headers:
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corpIn Express:
app.use((req,res,next)=>{res.setHeader('Cross-Origin-Opener-Policy','same-origin');res.setHeader('Cross-Origin-Embedder-Policy','require-corp');next();});Check the selected backend at runtime:
importThread,{detectRuntime}from'https://cdn.jsdelivr.net/npm/pthread.js@0.2.5/index.js';console.table(detectRuntime());constthread=newThread();console.log(thread.backend.kind);Native pthread in C:
#include<pthread.h>#include<stdio.h>void*run(void*arg) {
int*value=arg;
*value=*value*2;
returnarg;
}
intmain(void) {
pthread_tthread;
intvalue=21;
pthread_create(&thread, NULL, run, &value);
pthread_join(thread, NULL);
printf("%d\n", value);
return0;
}pthread.js:
importThreadfrom'pthread.js';constthread=newThread();awaitthread.pthread_create(asyncvalue=>value*2,21);constvalue=awaitthread.pthread_join();console.log(value);Native pthread synchronizes real OS threads and memory. pthread.js uses JavaScript workers when the platform allows it, and falls back to cooperative promises when it does not. The API shape is familiar, but JavaScript cannot expose every POSIX scheduling, signal, priority, or process-shared behavior exactly.
Implemented or simulated groups:
| Group | Functions |
|---|---|
| Thread lifecycle | pthread_create, pthread_join, pthread_exit, pthread_detach, pthread_self, pthread_equal |
| Cancellation | pthread_cancel, pthread_setcancelstate, pthread_setcanceltype, pthread_testcancel, pthread_cleanup_push, pthread_cleanup_pop |
| Mutexes | pthread_mutex_init, pthread_mutex_destroy, pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_timedlock, pthread_mutex_unlock |
| Mutex attributes | pthread_mutexattr_init, pthread_mutexattr_destroy, pthread_mutexattr_gettype, pthread_mutexattr_settype, pthread_mutexattr_getpshared, pthread_mutexattr_setpshared, pthread_mutexattr_getprotocol, pthread_mutexattr_setprotocol, pthread_mutexattr_getprioceiling, pthread_mutexattr_setprioceiling |
| Conditions | pthread_cond_init, pthread_cond_destroy, pthread_cond_wait, pthread_cond_timedwait, pthread_cond_signal, pthread_cond_broadcast |
| Condition attributes | pthread_condattr_init, pthread_condattr_destroy, pthread_condattr_getpshared, pthread_condattr_setpshared, pthread_condattr_getclock, pthread_condattr_setclock |
| Read-write locks | pthread_rwlock_init, pthread_rwlock_destroy, pthread_rwlock_rdlock, pthread_rwlock_tryrdlock, pthread_rwlock_wrlock, pthread_rwlock_trywrlock, pthread_rwlock_timedrdlock, pthread_rwlock_timedwrlock, pthread_rwlock_unlock |
| Read-write attributes | pthread_rwlockattr_init, pthread_rwlockattr_destroy, pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared, pthread_rwlockattr_getkind_np, pthread_rwlockattr_setkind_np |
| Thread attributes | pthread_attr_init, pthread_attr_destroy, pthread_attr_getdetachstate, pthread_attr_setdetachstate, pthread_attr_getschedpolicy, pthread_attr_setschedpolicy, pthread_attr_getschedparam, pthread_attr_setschedparam, pthread_attr_getinheritsched, pthread_attr_setinheritsched, pthread_attr_getscope, pthread_attr_setscope, pthread_attr_getstacksize, pthread_attr_setstacksize, pthread_attr_getstack, pthread_attr_setstack, pthread_attr_getguardsize, pthread_attr_setguardsize, pthread_attr_getstackaddr, pthread_attr_setstackaddr |
| TLS | pthread_key_create, pthread_key_delete, pthread_setspecific, pthread_getspecific |
| One-time init | pthread_once |
| Barriers | pthread_barrier_init, pthread_barrier_destroy, pthread_barrier_wait, pthread_barrierattr_init, pthread_barrierattr_destroy, pthread_barrierattr_getpshared, pthread_barrierattr_setpshared |
| Spin locks | pthread_spin_init, pthread_spin_destroy, pthread_spin_lock, pthread_spin_trylock, pthread_spin_unlock |
| Semaphores | sem_init, sem_destroy, sem_wait, sem_trywait, sem_timedwait, sem_post, sem_getvalue |
| Scheduling and names | pthread_getconcurrency, pthread_setconcurrency, pthread_setschedparam, pthread_getschedparam, pthread_setschedprio, pthread_getcpuclockid, pthread_getname_np, pthread_setname_np |
| Signals and platform extensions | pthread_kill, pthread_sigmask, pthread_atfork, pthread_getaffinity_np, pthread_setaffinity_np, pthread_getattr_np, pthread_attr_getaffinity_np, pthread_attr_setaffinity_np, pthread_getattr_default_np, pthread_setattr_default_np, pthread_timedjoin_np, pthread_tryjoin_np, pthread_clockjoin_np, pthread_yield_np, pthread_is_threaded_np |
Functions that cannot be represented in JavaScript return ENOSYS: pthread_mutex_consistent, pthread_mutex_consistent_np, robust mutex attribute helpers, priority ceiling helpers on live mutexes, and POSIX clock-lock variants.
The shared-memory backend also requires cross-origin isolation in browsers: Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp or equivalent.
| Platform | Shared-memory backend | Message-worker backend | Promise backend |
|---|---|---|---|
| Chrome desktop | 92+ | 61+ as ESM, older with bundling | 61+ as ESM |
| Edge desktop | 92+ | 79+ as ESM | 79+ as ESM |
| Firefox desktop | 79+ | 60+ as ESM | 60+ as ESM |
| Safari macOS | 15.2+ | 10.1+ as ESM | 10.1+ as ESM |
| Chrome Android | 89+ | 61+ as ESM | 61+ as ESM |
| Firefox Android | 79+ | 60+ as ESM | 60+ as ESM |
| Safari iOS | 15.2+ | 10.3+ as ESM | 10.3+ as ESM |
| Node.js | 12.17+ | 12.17+ | 12.17+ |
| Deno | 1.0+ | 1.0+ | 1.0+ |
| Bun | 1.0+ | 1.0+ | 1.0+ |
References: MDN SharedArrayBuffer, MDN Atomics, Chrome SharedArrayBuffer updates, MDN Web Workers, and Node.js worker_threads.
MIT. See LICENSE.md.