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
| Method | Parameters | Returns | Description |
|---|---|---|---|
| Constructor | — | Thread | Create empty thread |
| Constructor | func: F(None^)()^ | Thread^ | Create thread with function |
| spawn | func: F(None^)()^ | Thread^ | Create and start thread (static) |
Thread Control
| Method | Parameters | Returns | Description |
|---|---|---|---|
| join | — | Bool^ | Wait for thread to complete |
| detach | — | Bool^ | Detach thread (runs independently) |
| isJoinable | — | Bool^ | Check if thread can be joined |
Static Methods
| Method | Parameters | Returns | Description |
|---|---|---|---|
| sleep | milliseconds: Integer^ | None | Sleep current thread |
| yield | — | None | Yield to other threads |
| currentId | — | Integer^ | 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.
| Method | Parameters | Returns | Description |
|---|---|---|---|
| Constructor | — | Mutex | Create new mutex |
| lock | — | Bool^ | Acquire the lock (blocking) |
| unlock | — | Bool^ | Release the lock |
| tryLock | — | Bool^ | Try to acquire lock (non-blocking) |
| isValid | — | Bool^ | 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.
| Method | Parameters | Returns | Description |
|---|---|---|---|
| Constructor | mutex: Mutex& | LockGuard | Create guard (acquires lock) |
| ownsTheLock | — | Bool^ | Check if guard holds the lock |
| unlock | — | None | Manually 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.
| Method | Parameters | Returns | Description |
|---|---|---|---|
| Constructor | — | ConditionVariable | Create condition variable |
| wait | mutex: Mutex& | Bool^ | Wait until signaled |
| waitTimeout | mutex: Mutex&, timeoutMs: Integer^ | Integer^ | Wait with timeout |
| signal | — | Bool^ | Wake one waiting thread |
| broadcast | — | Bool^ | Wake all waiting threads |
| isValid | — | Bool^ | 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
| Method | Parameters | Returns | Description |
|---|---|---|---|
| Constructor | — | Atomic | Create with value 0 |
| Constructor | initialValue: Integer^ | Atomic^ | Create with initial value |
Access
| Method | Parameters | Returns | Description |
|---|---|---|---|
| get | — | Integer^ | Get current value |
| set | newValue: Integer^ | None | Set new value |
Atomic Operations
| Method | Parameters | Returns | Description |
|---|---|---|---|
| add | value: Integer^ | Integer^ | Add and return previous value |
| subtract | value: Integer^ | Integer^ | Subtract and return previous value |
| increment | — | Integer^ | Increment and return previous value |
| decrement | — | Integer^ | Decrement and return previous value |
| compareAndSwap | expected: Integer^, desired: Integer^ | Bool^ | CAS operation |
| exchange | newValue: 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.
| Method | Parameters | Returns | Description |
|---|---|---|---|
| Constructor | — | ThreadLocal | Create thread-local storage |
| get | — | T^ | Get value for current thread |
| set | value: T^ | None | Set value for current thread |
| isSet | — | Bool^ | Check if value is set |
| isValid | — | Bool^ | 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.
| Method | Parameters | Returns | Description |
|---|---|---|---|
| Constructor | — | Semaphore | Create with count 0 |
| Constructor | initialCount: Integer^ | Semaphore | Create with initial count |
| acquire | — | None | Decrement count (blocks if 0) |
| tryAcquire | — | Bool^ | Try to acquire (non-blocking) |
| release | — | None | Increment count |
| getCount | — | Integer^ | 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 ]