Class Signal() Foundation
Signal class to manage thread synchronization.
The Signal() function returns the class object for the Signal class, which implements a synchronization primitive based on event semaphores. A Signal object allows multiple threads or processes to coordinate their execution by signaling events and waiting for them to occur.
The Signal class provides a thread-safe mechanism for inter-thread communication where one or more threads can wait for an event to be signaled by another thread. When a signal is posted, all waiting threads are awakened. This pattern is useful for producer-consumer scenarios, thread coordination, and event-driven programming.
Key concepts:
- Event Semaphore: A synchronization object that can be in two states: signaled or non-signaled
- Signaling: Setting the semaphore to the signaled state, which releases waiting threads
- Waiting: Blocking thread execution until the semaphore becomes signaled
- Auto-reset: After a thread is released from waiting, the semaphore can be automatically reset to non-signaled state to ensure only one thread proceeds at a time
Use case scenarios:
1. Worker Thread Coordination: A main thread creates multiple worker threads that process data in parallel. Each worker signals completion using a Signal object. The main thread waits for all workers to complete before proceeding with result aggregation.
2. Event Notification System: A monitoring thread watches for file system changes or network events. When an event occurs, it signals waiting threads that are responsible for handling specific types of events, enabling responsive event-driven architecture.
// Use case 1: Producer-Consumer pattern with timeout
// Producer thread signals when data is ready
PROCEDURE ProducerThread(oSignal, aSharedData)
LOCAL nCount := 1
DO WHILE nCount <= 10
Sleep(100) // Simulate work
AAdd(aSharedData, "Item " + Str(nCount))
oSignal:signal() // Wake up consumer
nCount++
ENDDO
RETURN
// Consumer thread waits for signal with 5 second timeout
PROCEDURE ConsumerThread(oSignal, aSharedData)
LOCAL lSuccess
DO WHILE .T.
lSuccess := oSignal:wait(500) // Wait up to 5 seconds
IF lSuccess
IF Len(aSharedData) > 0
? "Processed:", ATail(aSharedData)
ASize(aSharedData, Len(aSharedData)-1)
ENDIF
ELSE
? "Timeout - no data received"
EXIT
ENDIF
ENDDO
RETURN
// Use case 2: Parallel task coordination
// Wait for multiple worker threads to complete their tasks
PROCEDURE Main()
LOCAL aSignals := {}
LOCAL aThreads := {}
LOCAL i, oSignal
// Create signals and start worker threads
FOR i := 1 TO 3
oSignal := Signal():new()
oSignal:cargo := "Task" + Str(i)
AAdd(aSignals, oSignal)
AAdd(aThreads, Thread():new():start({|o| WorkerTask(o)}, oSignal))
NEXT
? "Waiting for all tasks to complete..."
IF Signal():waitAll(aSignals, 1000) // Wait up to 10 seconds
? "All tasks completed successfully!"
FOR i := 1 TO Len(aSignals)
? "Completed:", aSignals[i]:cargo
NEXT
ELSE
? "Timeout - not all tasks completed"
ENDIF
RETURN
PROCEDURE WorkerTask(oSignal)
LOCAL nDelay
// Simulate variable working times from 1000 to 3000 ms
nDelay := RandomInt( 1000, 3000 )
Sleep(nDelay/10)
// Provide result and signal completed
oSignal:cargo += " - Done in " + Str(nDelay) + " ms"
oSignal:signal() // Signal completion
RETURN
If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.