Thread System ($thread
)
Overview
Grapa's $thread
system provides a complete coroutine and threading implementation with full synchronization primitives, condition variables, and cooperative multitasking capabilities. This is not a planned feature - it's already fully implemented and powers Grapa's own execution pipeline.
✅ Sleep Function in Multi-Threaded Applications
Good News: Grapa's .sleep()
function works correctly in multi-threaded applications with proper thread-local behavior.
Thread-Safe Sleep Behavior
- Sleep calls are thread-local - each thread can sleep independently
- Concurrent sleep calls work correctly - multiple threads can sleep simultaneously
- Sleep duration is respected per thread - each thread sleeps for its specified duration
- No blocking between threads - one thread's sleep doesn't block others
Example of Proper Sleep Behavior
/* This demonstrates proper multi-threaded sleep behavior */
thread1 = $thread();
thread2 = $thread();
/* Thread 1: 3 second sleep */
thread1.start(
op() {
"Thread 1: Starting 3 second sleep".echo();
3000.sleep(); /* 3 seconds */
"Thread 1: Sleep completed".echo();
return "Done";
},
null,
null
);
/* Main thread: 50ms sleep */
"Main: Starting 50ms sleep".echo();
50.sleep(); /* Takes exactly 50ms, independent of thread1 */
/* Both sleeps run concurrently and complete at their respective times */
How It Works
- Grapa's sleep implementation provides proper thread isolation
- Each thread maintains its own sleep state without interfering with others
- Sleep calls complete independently based on their individual durations
- Thread coordination works seamlessly with sleep, suspend, and resume
Best Practices
- Use sleep freely in multi-threaded code - it works correctly
- Combine sleep with suspend/resume for advanced thread coordination
- Use sleep for timing delays without worrying about thread interference
- Sleep works well with locks and condition variables for complex synchronization
Key Features
- Complete Coroutine Support: Full suspend/resume capabilities
- Synchronization Primitives: Locks, condition variables, trylock operations
- Cross-Platform: Consistent behavior across Windows, Linux, and macOS
- High Performance: Optimized critical sections and condition variables
- Thread Safety: Built-in protection against race conditions
- Production Ready: Powers Grapa's lexer→compiler→executor pipeline
Thread Object Creation
/* Create a new thread object */
thread = $thread();
Core Thread Management
start(runCode, param, doneCode)
Start a thread with execution code and callbacks.
Parameters:
- runCode
: Function to execute in the thread
- param
: Parameter to pass to the run function (optional)
- doneCode
: Completion callback function (optional)
Returns: Error code (0 = success, -1 = failure)
Example:
thread = $thread();
thread.start(
op(input) {
"Thread starting with input: ".echo() + input.echo();
/* Note: Avoid sleep() in multi-threaded code */
return "Thread completed";
},
"Hello from main thread", /* Parameter */
op(input, result) {
"Thread finished with result: ".echo() + result.echo();
}
);
stop()
Stop the thread gracefully.
Parameters: None
Returns: Error code
Example:
thread = $thread();
thread.start(op() { /* long running work */ }, null, null);
/* Use suspend/resume instead of sleep for coordination */
thread.suspend();
thread.stop();
started()
Check if thread is currently running.
Parameters: None
Returns: Boolean (true = running, false = stopped)
Example:
thread = $thread();
("Thread started: " + thread.started()).echo(); /* false */
thread.start(op() { /* work without sleep */ }, null, null);
("Thread started: " + thread.started()).echo(); /* true */
Coroutine Control
suspend()
Pause thread execution (coroutine suspend).
Parameters: None
Returns: Error code
Example:
thread = $thread();
thread.start(
op() {
"Starting work".echo();
/* Use suspend instead of sleep for coordination */
"About to suspend".echo();
thread.suspend(); /* Suspend self */
"Resumed from suspension".echo();
return "Completed";
},
null,
null
);
/* Resume the suspended thread */
thread.resume();
resume()
Resume suspended thread (coroutine resume).
Parameters: None
Returns: Error code
Example:
/* Resume a suspended thread */
if (thread.suspended()) {
thread.resume();
}
suspended()
Check if thread is currently suspended.
Parameters: None
Returns: Boolean (true = suspended, false = running)
Example:
thread = $thread();
("Thread suspended: " + thread.suspended()).echo(); /* false */
thread.start(
op() {
thread.suspend();
},
null,
null
);
("Thread suspended: " + thread.suspended()).echo(); /* true */
Synchronization Primitives
trylock()
Try to acquire lock (non-blocking).
Parameters: None
Returns: Boolean (true = acquired, false = failed)
Example:
lock = $thread();
/* Try to acquire lock */
if (lock.trylock()) {
"Lock acquired".echo();
lock.unlock();
} else {
"Lock busy".echo();
}
lock()
Acquire lock (blocking).
Parameters: None
Returns: Error code
Example:
lock = $thread();
/* Block until lock is available */
lock.lock();
"Critical section".echo();
lock.unlock();
unlock()
Release lock.
Parameters: None
Returns: Error code
Example:
lock = $thread();
lock.lock();
/* Critical section code */
lock.unlock();
Condition Variables
wait()
Wait for signal (condition variable).
Parameters: None
Returns: Error code
Example:
condition = $thread();
data_ready = false;
/* Producer thread */
producer = $thread();
producer.start(
op() {
/* Use suspend/resume instead of sleep */
producer.suspend();
data_ready = true;
condition.signal();
return "Producer done";
},
null,
null
);
/* Consumer thread */
consumer = $thread();
consumer.start(
op() {
while (!data_ready) {
condition.wait();
};
"Data is ready!".echo();
return "Consumer done";
},
null,
null
);
signal()
Signal waiting threads.
Parameters: None
Returns: Error code
Example:
condition = $thread();
/* Wake up waiting threads */
condition.signal();
waiting()
Check if thread is waiting for signal.
Parameters: None
Returns: Boolean (true = waiting, false = not waiting)
Example:
condition = $thread();
/* Check if any threads are waiting */
if (condition.waiting()) {
"Threads are waiting".echo();
} else {
"No threads waiting".echo();
}
Utility Methods
type()
Get the type of the thread object.
Parameters: None
Returns: String ("$thread")
Example:
thread = $thread();
("Thread type: " + thread.type()).echo(); /* "$thread" */
describe()
Get a description of the thread object.
Parameters: None
Returns: String description
Example:
thread = $thread();
thread.describe().echo();
Working Thread Examples
The following examples demonstrate working thread patterns with proper sleep behavior:
Example 1: Basic Thread Lifecycle
/* Basic thread creation and management */
basic_thread = $thread();
basic_thread.start(
op() {
"Basic thread: Starting work".echo();
/* Note: 3000.sleep() works here because it's the only sleep */
"Basic thread: Work completed".echo();
return ("Basic thread result");
},
0,
op(input, result) {
("Basic thread callback: " + result).echo();
}
);
/* Wait for thread completion */
while(basic_thread.started()==false) ;
while(basic_thread.started()==true) ;
"Main: Basic thread done".echo();
Example 2: Coroutine Suspend/Resume
/* Coroutine pattern using suspend/resume */
coroutine = $thread();
coroutine.start(
op() {
"Coroutine: Starting".echo();
"Coroutine: About to suspend".echo();
coroutine.suspend();
"Coroutine: Resumed from suspension".echo();
"Coroutine: Completed".echo();
return ("Coroutine completed");
},
null,
op(input, result) {
("Coroutine callback: " + result).echo();
}
);
/* Coordinate with suspend/resume instead of sleep */
while(coroutine.suspended()==false) ;
while(coroutine.suspended()==true) ;
"Main: Resuming coroutine".echo();
coroutine.resume();
while(coroutine.started()==true) ;
Example 3: Thread-Safe Counter with Lock
/* Thread-safe counter using locks */
counter_worker = [];
shared_counter = 0;
counter_lock = $thread();
for (i = 0; i < 3; i+=1) {
counter_worker += $thread();
counter_worker[i].start(
op(worker_id) {
counter_worker[worker_id].suspend();
for (j = 0; j < 5; j+=1) {
counter_lock.lock();
shared_counter += 1;
$local.current = shared_counter;
counter_lock.unlock();
("Worker " + worker_id + ": Counter = " + current).echo();
};
return ("Worker " + worker_id + " completed");
},
i,
op(input, result) {
("Counter worker callback: " + result).echo();
}
);
};
/* Coordinate workers using suspend/resume */
for (i = 0; i < 3; i+=1)
while(counter_worker[i].suspended()==false) ;
for (i = 0; i < 3; i+=1)
counter_worker[i].resume();
for (i = 0; i < 3; i+=1)
while(counter_worker[i].started()==false) ;
("Final counter value: " + shared_counter).echo();
Example 4: Producer-Consumer Pattern
/* Producer-consumer with proper coordination */
consumer = [];
shared_queue = [];
queue_lock = $thread();
consumer_count = 3;
consumer_message_count = 4;
/* Consumer threads */
for(consumer_id=0;consumer_id<consumer_count;consumer_id+=1) {
consumer += $thread();
consumer[-1].start(
op(id) {
("Consumer " + id + ": Starting consumption").echo();
$local.items_consumed = 0;
while (items_consumed < consumer_message_count) {
queue_lock.lock();
while (shared_queue.len() == 0) {
queue_lock.unlock();
consumer[id].suspend(); /* Use suspend instead of sleep */
queue_lock.lock();
};
item = shared_queue[0];
shared_queue -= shared_queue[0];
("Consumer " + id + ": extracted: " + item).echo();
queue_lock.unlock();
/* Note: tm.sleep() works here because it's coordinated */
$local.tm = 100 * 4.random();
("Consumer " + id + ": sleeping: " + tm + "ms").echo();
tm.sleep();
("Consumer " + id + ": consumed: " + item).echo();
items_consumed += 1;
};
return ("Consumer " + id + " completed: " + items_consumed);
},
consumer_id,
op(input, result) {
("Consumer callback: " + result).echo();
}
);
};
/* Producer thread */
producer = $thread();
producer.start(
op() {
producer.suspend();
$local.i = 0;
while(i<producer_message_count) {
queue_lock.lock();
shared_queue += "Item " + i;
queue_lock.unlock();
/* Resume suspended consumers */
for(consumer_id=0;consumer_id<consumer_count;consumer_id+=1) {
if (consumer[consumer_id].suspended()) {
consumer[consumer_id].resume();
};
};
i += 1;
};
return ("Producer completed");
},
null,
op(input, result) {
("Producer callback: " + result).echo();
}
);
/* Coordinate using suspend/resume */
while(producer.suspended()==false) ;
producer.resume();
while(producer.started()==true) ;
for(consumer_id=0;consumer_count;consumer_id+=1)
while(consumer[consumer_id].started()) ;
Best Practices for Multi-Threaded Code
1. Avoid Sleep in Multi-Threaded Applications
/* BAD: Sleep can cause coordination issues */
thread1.start(op() { 1000.sleep(); }, null, null);
thread2.start(op() { 500.sleep(); }, null, null);
/* GOOD: Use suspend/resume for coordination */
thread1.start(op() { thread1.suspend(); }, null, null);
thread2.start(op() { thread2.suspend(); }, null, null);
2. Use Suspend/Resume for Thread Coordination
/* Coordinate threads without sleep */
worker = $thread();
worker.start(
op() {
"Worker starting".echo();
worker.suspend(); /* Wait for resume */
"Worker resumed".echo();
return "Done";
},
null,
null
);
/* Main thread coordinates */
while(worker.suspended()==false) ;
worker.resume();
while(worker.started()==true) ;
3. Use Locks for Shared Resource Protection
/* Protect shared resources with locks */
$global shared_data = [];
$global data_lock = $thread();
worker = $thread();
worker.start(
op() {
data_lock.lock();
shared_data += "new item";
data_lock.unlock();
return "Done";
},
null,
null
);
4. Use Condition Variables for Signaling
/* Signal between threads without sleep */
$global data_ready = false;
$global ready_condition = $thread();
producer = $thread();
producer.start(
op() {
data_ready = true;
ready_condition.signal();
return "Done";
},
null,
null
);
consumer = $thread();
consumer.start(
op() {
while (!data_ready) {
ready_condition.wait();
};
"Data is ready!".echo();
return "Done";
},
null,
null
);
Performance Characteristics
Thread Creation Overhead
- Linux/Mac (pthread): ~1-2ms per thread
- Windows (CreateThread): ~2-3ms per thread
- Memory overhead: ~1-2MB per thread (stack + context)
Synchronization Performance
- Critical Section: ~50-100ns lock/unlock
- Mutex: ~100-200ns lock/unlock
- Condition Variable: ~1-5μs wait/signal
Scalability Considerations
/* Recommended thread limits */
thread_limits = {
windows: 2000, /* Windows thread limit */
linux: 32768, /* Linux thread limit */
mac: 2048 /* macOS thread limit */
};
/* Practical limits for Grapa */
practical_limits = {
small_system: 8, /* 4-8 cores */
medium_system: 16, /* 8-16 cores */
large_system: 32 /* 16+ cores */
};
Integration with Grapa's Execution Pipeline
Grapa's $thread
system powers the language's own execution pipeline:
- Lexer Thread: Processes input text and generates tokens
- Compiler Thread: Converts tokens to execution trees
- Executor Thread: Executes the compiled code
Each stage uses suspend()
, resume()
, wait()
, and signal()
to coordinate:
- Lexer suspends when input queue is empty
- Compiler suspends when token queue is empty
- Executor suspends when code queue is empty
- Each stage signals the next when data is available
This demonstrates the system's production readiness and reliability.
Cross-Platform Compatibility
The $thread
system provides consistent behavior across all supported platforms:
- Windows: Uses Windows API (CreateThread, CRITICAL_SECTION, WaitOnAddress)
- Linux/Mac: Uses POSIX threads (pthread_create, pthread_mutex, pthread_cond)
- Abstraction Layer: Common interface across all platforms
- Error Handling: Consistent error reporting across platforms
Thread-Safe Variable Declarations
When writing concurrent code in Grapa, it's essential to use proper thread-safe variable declarations. See Thread-Safe Variable Declarations for comprehensive guidance on:
- Using
$global
for explicitly shared variables - Protecting shared variables with locks
- Avoiding race conditions
- Best practices for concurrent programming
Related Documentation
- Thread-Safe Variable Declarations - Comprehensive guide to thread-safe programming
- Thread Examples - Working thread examples with proper sleep behavior
Conclusion
Grapa's $thread
system provides world-class coroutine and threading capabilities that are:
- Fully Implemented: All methods are working and tested
- Production Ready: Powers Grapa's own execution pipeline
- Cross-Platform: Consistent behavior across Windows, Linux, and macOS
- High Performance: Optimized for real-world usage
- Thread Safe: Built-in protection against race conditions
- Coroutine Ready: Full suspend/resume capabilities
Important Note: The system is robust and feature-complete, with the .sleep()
function working correctly in multi-threaded applications. Each thread can sleep independently without blocking others, making it safe to use sleep in concurrent programming scenarios.