5.2.10. C Integration: Threading
This tutorial demonstrates how to use daslang contexts and compilation
pipelines across multiple threads from a pure C host application using
the daScriptC.h API.
Topics covered:
Part A — Running a compiled context on a worker thread
Part B — Compiling a script from scratch on a worker thread
das_environment_get_bound()/das_environment_set_bound()— thread-local environment bindingdas_reuse_cache_guard_create()/das_reuse_cache_guard_release()— thread-local free-list cache managementdas_context_clone()withDAS_CONTEXT_CATEGORY_THREAD_CLONEDAS_POLICY_THREADLOCK_CONTEXT— context mutex for threads
5.2.10.1. Prerequisites
Tutorial 1 completed (tutorial_integration_c_hello_world) — basic compile → simulate → eval cycle.
Familiarity with platform threading primitives (
_beginthreadexon Windows,pthread_createon POSIX).
5.2.10.2. Why threading matters
daslang uses thread-local storage (TLS) for its environment object. Every thread that touches the daslang C API must have a valid environment bound. There are two common patterns:
Share the environment — the worker thread binds the same environment as the main thread via
das_environment_set_bound(). Use this when the worker only executes and the main thread is idle.Independent environment — the worker thread calls
das_initialize()/das_shutdown()to create and destroy its own module registry and compilation pipeline.
5.2.10.3. New C API functions for threading
These functions were added to daScriptC.h specifically for
multi-threaded host applications:
Function |
Purpose |
|---|---|
|
Return the environment bound to the calling thread (TLS). |
|
Bind an environment on the calling thread. |
|
Create a thread-local free-list cache guard (call first on any worker thread). |
|
Release the guard (call before thread exit). |
|
Clone a context for use on another thread. |
|
Category constant for thread-owned clones. |
5.2.10.4. The daslang script
A simple script that computes the sum 0 + 1 + … + 99 = 4950:
options gen2
[export]
def compute() : int {
var total = 0
for (i in range(100)) {
total += i
}
return total
}
5.2.10.5. Part A — Run on a worker thread
Compile and simulate on the main thread, then clone the context and run it on a worker thread.
// Compile with threadlock_context enabled
das_policies * pol = das_policies_make();
das_policies_set_bool(pol, DAS_POLICY_THREADLOCK_CONTEXT, 1);
das_program * prog = das_program_compile_policies(path, fac, tout, lib, pol);
das_policies_release(pol);
// Simulate on the main thread
das_context * ctx = das_context_make(das_program_context_stack_size(prog));
das_program_simulate(prog, ctx, tout);
// Clone the context for the worker thread
das_context * clone = das_context_clone(ctx,
DAS_CONTEXT_CATEGORY_THREAD_CLONE);
// Capture the environment
das_environment * env = das_environment_get_bound();
// On the worker thread:
das_environment_set_bound(env);
das_function * fn = das_context_find_function(clone, "compute");
vec4f res = das_context_eval_with_catch(clone, fn, NULL);
int result = das_argument_int(res);
Key points:
Function |
Explanation |
|---|---|
|
Returns the current thread’s TLS environment pointer. Must be captured before launching the worker. |
|
Binds the environment on the worker thread. Without this, any daslang C API call will crash. |
|
Creates a new context that shares the simulated program.
Release with |
|
Marks the clone as thread-owned for diagnostics and safety. |
|
Compile-time policy that gives the context a mutex. Required when the context (or its clone) runs on a non-main thread. |
5.2.10.6. Part B — Compile on a worker thread
Create a fully independent daslang environment on a new thread.
// On the worker thread:
// 1. Thread-local free-list cache — must be first.
das_reuse_cache_guard * guard = das_reuse_cache_guard_create();
// 2+3. Register modules + create environment in TLS.
das_initialize();
// 4. Standard compile → simulate → eval cycle.
das_policies * pol = das_policies_make();
das_policies_set_bool(pol, DAS_POLICY_THREADLOCK_CONTEXT, 1);
das_program * prog = das_program_compile_policies(path, fac, tout, lib, pol);
das_policies_release(pol);
das_context * ctx = das_context_make(das_program_context_stack_size(prog));
das_program_simulate(prog, ctx, tout);
das_function * fn = das_context_find_function(ctx, "compute");
vec4f res = das_context_eval_with_catch(ctx, fn, NULL);
int result = das_argument_int(res);
// Cleanup
das_context_release(ctx);
das_program_release(prog);
/* ... release fac, lib, tout ... */
// 5. Shut down this thread's module system.
das_shutdown();
das_reuse_cache_guard_release(guard);
Key points:
Function |
Explanation |
|---|---|
|
Initializes per-thread free-list caches. Must be created first on any thread that uses daslang. |
|
Registers module factories and creates a new environment in TLS. Safe to call on multiple threads — module registration is idempotent. |
|
Destroys this thread’s modules and environment. Must be called before the thread exits. |
|
Tears down thread-local caches. Call after
|
|
Same policy as Part A — ensures the context has a mutex. |
5.2.10.7. Choosing the right pattern
Criteria |
Part A (clone + run) |
Part B (compile on thread) |
|---|---|---|
Compilation cost |
Zero on worker (pre-compiled) |
Full compilation on worker |
Isolation |
Shares environment with main |
Fully independent |
Concurrent compilation |
Not safe (shared env) |
Safe (separate env per thread) |
Use case |
Game threads running pre-compiled AI/logic |
Build servers, parallel test runners |
5.2.10.8. Portable threading
The tutorial uses _beginthreadex on Windows and pthread_create
on POSIX, wrapped in a small helper. The DAS_C_INTEGRATION_TUTORIAL
CMake macro already links Threads::Threads, so no extra setup is
needed for pthreads.
5.2.10.9. Build & run
cmake --build build --config Release --target integration_c_10
bin/Release/integration_c_10
Expected output:
=== Part A: Run on a worker thread ===
compute() on worker thread returned: 4950
PASS
=== Part B: Compile on a worker thread ===
compute() compiled + run on worker thread returned: 4950
PASS
See also
Full source:
10_threading.c,
10_threading.das
Previous tutorial: tutorial_integration_c_aot
C++ equivalent: tutorial_integration_cpp_threading
daScriptC.h API header: include/daScript/daScriptC.h