Class Signal() Foundation
Class function of the Signal class.
Signal objects are used to control program flow within one or more threads from one other thread. To achieve this, it is necessary that one and the same Signal object is visible in at least two threads. Therefore, Signal objects can only be used in conjunction with Thread objects. In other words, at least one additional Thread object must exist in an application for the Signal class to become useful (note: the Main procedure is executed by an implicit Thread object).
There are two methods in the Signal class: :signal() and :wait(). The method :signal() triggers a signal, while the :wait() method causes a thread to enter a wait state. If a thread executes the :wait() method, it waits for the signal and suspends program execution. The thread resumes as soon as a second thread executes the :signal() method with the same Signal object.
With the aid of Signal objects it becomes possible for the current thread to control program flow in other threads. Each thread which executes the :wait() method enters a wait state until another thread executes the :signal() method.
// A simple screen saver for text mode applications is programmed
// in this example. The code for the screen saver runs in
// a separate thread which waits to be signalled for a maximum of
// 5 seconds. If no signal is triggered, the screen saver is
// activated. The thread is signalled from the Main procedure
// each time an event (keyboard, mouse) is taken from the
// event queue.
#include "AppEvent.ch"
PROCEDURE Main
LOCAL nEvent, oThread, oSignal
? "Press a key. ESC quits"
oThread := Thread():new()
oSignal := Signal():new()
oThread:start( "ScreenSaver", oSignal, 5 )
DO WHILE nEvent <> xbeK_ESC
nEvent := AppEvent(,,,0)
oSignal:signal()
? "Event =", nEvent
ENDDO
RETURN
** Procedure runs in separate thread
PROCEDURE ScreenSaver( oSignal, nSeconds )
LOCAL cScreen, cTemp
DO WHILE .T.
IF .NOT. oSignal:wait( nSeconds * 100 )
// This code is executed if no signal is triggered
// for more than <nSeconds> seconds
cScreen := SaveScreen( 0,0, MaxRow(), MaxCol() )
cTemp := SubStr( cScreen, 2 ) + Left( cScreen, 1 )
// Change screen until thread is signalled
DO WHILE .NOT. oSignal:wait(10)
cTemp := SubStr( cTemp, 3 ) + Left( cTemp, 2 )
RestScreen( 0,0, MaxRow(), MaxCol(), cTemp )
ENDDO
RestScreen( 0,0, MaxRow(), MaxCol(), cScreen )
cScreen := ;
cTemp := NIL
ENDIF
ENDDO
RETURN
// A new database is created in this example and records from
// an existing database are appended. An array is used as a
// read/write buffer to transfer data from the existing to the
// new database. Reading and writing data runs simultaneously
// in two threads. Two Signal objects coordinate which thread
// may read and which one may write. A third signal causes
// the second thread to terminate.
PROCEDURE Main
LOCAL oReadDone, oWriteDone, oDoExit, oThread, aValues
USE LargeDB
DbCreate( "Test", DbStruct() )
oThread := Thread():new()
aValues := Array( FCount() )
oReadDone := Signal():new()
oWriteDone := Signal():new()
oDoExit := Signal():new()
oThread:start( "AppendTo", "Test" , aValues , ;
oReadDone, oWriteDone, oDoExit )
oWriteDone:wait() // Wait until 2nd database
// is open
DO WHILE .T. // Transfer record to array
Aeval( aValues, {|x,i| x:=FieldGet(i) },,, .T. )
IF ! Eof()
oReadDone:signal() // 1st signal: record is read
SKIP
ELSE
oDoExit:signal() // 2nd signal: terminate thread #2
EXIT
ENDIF
oWriteDone:wait() // Wait until data is written
ENDDO // to new database
oThread:synchronize(0)
USE
RETURN
** Procedure runs in separate thread
PROCEDURE AppendTo( cDbFile, aValues, ;
oReadDone, oWriteDone, oDoExit )
USE (cDbFile) EXCLUSIVE
oWriteDone:signal() // Signal: database is open
DO WHILE .T.
IF oReadDone:wait(10) // Check if record is read
DbAppend() // Write data
AEval( aValues, {|x,i| FieldPut(i,x) } )
oWriteDone:signal() // Signal: Data is written
ELSEIF oDoExit:wait(10) // Got an Exit signal?
EXIT
ENDIF
ENDDO
USE
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.