Concurrent Module

The Language::Concurrent module provides multi-threading primitives for parallel execution and synchronization.

xxml
#import Language::Concurrent;

Warning

Multi-threaded programming requires careful consideration of data races and deadlocks. Always use proper synchronization primitives when accessing shared data.

Thread

Represents an independent thread of execution.

Creating Threads

MethodParametersReturnsDescription
ConstructorThreadCreate empty thread
Constructorfunc: F(None^)()^Thread^Create thread with function
spawnfunc: F(None^)()^Thread^Create and start thread (static)

Thread Control

MethodParametersReturnsDescription
joinBool^Wait for thread to complete
detachBool^Detach thread (runs independently)
isJoinableBool^Check if thread can be joined

Static Methods

MethodParametersReturnsDescription
sleepmilliseconds: Integer^NoneSleep current thread
yieldNoneYield to other threads
currentIdInteger^Get current thread ID
xxml
// Spawn a new thread
Instantiate Concurrent::Thread^ As <worker> = Concurrent::Thread::spawn(
    Lambda () -> None^ {
        Run System::Console::printLine(String::Constructor("Hello from thread!"));
        Return None::Constructor();
    }
);

// Wait for thread to complete
Run worker.join();
Run System::Console::printLine(String::Constructor("Thread finished!"));

// Sleep current thread for 1 second
Run Concurrent::Thread::sleep(Integer::Constructor(1000));

Mutex

Mutual exclusion lock for protecting shared resources.

MethodParametersReturnsDescription
ConstructorMutexCreate new mutex
lockBool^Acquire the lock (blocking)
unlockBool^Release the lock
tryLockBool^Try to acquire lock (non-blocking)
isValidBool^Check if mutex is valid
xxml
Instantiate Concurrent::Mutex^ As <mutex> = Concurrent::Mutex::Constructor();
Instantiate Integer^ As <counter> = Integer::Constructor(0);

// In each thread:
Run mutex.lock();
Set counter = counter.add(Integer::Constructor(1));
Run mutex.unlock();

LockGuard

RAII-style lock that automatically unlocks when destroyed.

MethodParametersReturnsDescription
Constructormutex: Mutex&LockGuardCreate guard (acquires lock)
ownsTheLockBool^Check if guard holds the lock
unlockNoneManually release lock
xxml
Instantiate Concurrent::Mutex^ As <mutex> = Concurrent::Mutex::Constructor();

// LockGuard automatically locks on creation
{
    Instantiate Concurrent::LockGuard^ As <guard> = Concurrent::LockGuard::Constructor(mutex);
    // Critical section - mutex is locked
    Run System::Console::printLine(String::Constructor("Inside critical section"));
    // Mutex automatically unlocked when guard goes out of scope
}

Note

LockGuard follows the RAII pattern. The mutex is automatically released when the guard goes out of scope, even if an exception occurs.

ConditionVariable

Synchronization primitive for thread coordination.

MethodParametersReturnsDescription
ConstructorConditionVariableCreate condition variable
waitmutex: Mutex&Bool^Wait until signaled
waitTimeoutmutex: Mutex&, timeoutMs: Integer^Integer^Wait with timeout
signalBool^Wake one waiting thread
broadcastBool^Wake all waiting threads
isValidBool^Check if valid
xxml
Instantiate Concurrent::Mutex^ As <mutex> = Concurrent::Mutex::Constructor();
Instantiate Concurrent::ConditionVariable^ As <cv> = Concurrent::ConditionVariable::Constructor();
Instantiate Bool^ As <ready> = Bool::Constructor(false);

// Consumer thread
Run mutex.lock();
While (ready.not().toBool())
{
    Run cv.wait(mutex);
}
// Process data...
Run mutex.unlock();

// Producer thread (in another thread)
Run mutex.lock();
Set ready = Bool::Constructor(true);
Run cv.signal();
Run mutex.unlock();

Atomic

Lock-free atomic integer for thread-safe operations.

Constructors

MethodParametersReturnsDescription
ConstructorAtomicCreate with value 0
ConstructorinitialValue: Integer^Atomic^Create with initial value

Access

MethodParametersReturnsDescription
getInteger^Get current value
setnewValue: Integer^NoneSet new value

Atomic Operations

MethodParametersReturnsDescription
addvalue: Integer^Integer^Add and return previous value
subtractvalue: Integer^Integer^Subtract and return previous value
incrementInteger^Increment and return previous value
decrementInteger^Decrement and return previous value
compareAndSwapexpected: Integer^, desired: Integer^Bool^CAS operation
exchangenewValue: Integer^Integer^Set and return previous value
xxml
Instantiate Concurrent::Atomic^ As <counter> = Concurrent::Atomic::Constructor(
    Integer::Constructor(0)
);

// Thread-safe increment (no mutex needed)
Run counter.increment();

// Atomic add
Run counter.add(Integer::Constructor(10));

// Compare-and-swap
Instantiate Bool^ As <success> = counter.compareAndSwap(
    Integer::Constructor(11),  // expected
    Integer::Constructor(20)   // desired
);

Run System::Console::printLine(
    String::Constructor("Counter: ").append(counter.get().toString())
);

ThreadLocal

Thread-local storage for per-thread data.

MethodParametersReturnsDescription
ConstructorThreadLocalCreate thread-local storage
getT^Get value for current thread
setvalue: T^NoneSet value for current thread
isSetBool^Check if value is set
isValidBool^Check if storage is valid
xxml
// Each thread gets its own copy
Instantiate Concurrent::ThreadLocal<String>^ As <threadName> =
    Concurrent::ThreadLocal@String::Constructor();

// Set in current thread
Run threadName.set(String::Constructor("MainThread"));

// Get in current thread
If (threadName.isSet().toBool())
{
    Instantiate String^ As <name> = threadName.get();
    Run System::Console::printLine(name);
}

Semaphore

Counting semaphore for limiting concurrent access.

MethodParametersReturnsDescription
ConstructorSemaphoreCreate with count 0
ConstructorinitialCount: Integer^SemaphoreCreate with initial count
acquireNoneDecrement count (blocks if 0)
tryAcquireBool^Try to acquire (non-blocking)
releaseNoneIncrement count
getCountInteger^Get current count
xxml
// Limit concurrent connections to 3
Instantiate Concurrent::Semaphore^ As <pool> = Concurrent::Semaphore::Constructor(
    Integer::Constructor(3)
);

// Acquire a slot (blocks if all slots in use)
Run pool.acquire();
// ... do work with limited resource ...
Run pool.release();

// Non-blocking try
If (pool.tryAcquire().toBool())
{
    // Got a slot
    // ... do work ...
    Run pool.release();
}
Else
{
    Run System::Console::printLine(String::Constructor("All slots busy"));
}

Complete Example

producer_consumer.xxml
1#import Language::Core;
2#import Language::Concurrent;
3#import Language::Collections;
4#import Language::System;
5
6[ Entrypoint
7 {
8 // Shared state
9 Instantiate Concurrent::Mutex^ As <mutex> = Concurrent::Mutex::Constructor();
10 Instantiate Concurrent::ConditionVariable^ As <notEmpty> =
11 Concurrent::ConditionVariable::Constructor();
12 Instantiate Concurrent::ConditionVariable^ As <notFull> =
13 Concurrent::ConditionVariable::Constructor();
14 Instantiate Collections::Queue<Integer>^ As <queue> =
15 Collections::Queue@Integer::Constructor();
16 Instantiate Concurrent::Atomic^ As <done> = Concurrent::Atomic::Constructor(
17 Integer::Constructor(0)
18 );
19
20 // Producer thread
21 Instantiate Concurrent::Thread^ As <producer> = Concurrent::Thread::spawn(
22 Lambda () -> None^ {
23 For (Instantiate Integer^ As <i> = Integer::Constructor(0);
24 i.lessThan(Integer::Constructor(10)).toBool();
25 Set i = i.add(Integer::Constructor(1)))
26 {
27 Run mutex.lock();
28
29 // Wait if queue is full (max 5 items)
30 While (queue.size().greaterOrEqual(Integer::Constructor(5)).toBool())
31 {
32 Run notFull.wait(mutex);
33 }
34
35 Run queue.enqueue(i);
36 Run System::Console::printLine(
37 String::Constructor("Produced: ").append(i.toString())
38 );
39
40 Run notEmpty.signal();
41 Run mutex.unlock();
42
43 Run Concurrent::Thread::sleep(Integer::Constructor(100));
44 }
45
46 Run done.set(Integer::Constructor(1));
47 Run notEmpty.broadcast();
48 Return None::Constructor();
49 }
50 );
51
52 // Consumer thread
53 Instantiate Concurrent::Thread^ As <consumer> = Concurrent::Thread::spawn(
54 Lambda () -> None^ {
55 While (true)
56 {
57 Run mutex.lock();
58
59 // Wait for items
60 While (queue.isEmpty().toBool())
61 {
62 If (done.get().equals(Integer::Constructor(1)).toBool())
63 {
64 Run mutex.unlock();
65 Return None::Constructor();
66 }
67 Run notEmpty.wait(mutex);
68 }
69
70 Instantiate Integer^ As <item> = queue.dequeue();
71 Run System::Console::printLine(
72 String::Constructor("Consumed: ").append(item.toString())
73 );
74
75 Run notFull.signal();
76 Run mutex.unlock();
77
78 Run Concurrent::Thread::sleep(Integer::Constructor(150));
79 }
80
81 Return None::Constructor();
82 }
83 );
84
85 // Wait for threads to complete
86 Run producer.join();
87 Run consumer.join();
88
89 Run System::Console::printLine(String::Constructor("All done!"));
90 Exit(0);
91 }
92]

See Also