Smalltalk allows multiple lightweight processes (also called threads or tasks) to execute pseudo concurrently. These run within the same address space (inside a single heavy weight operating system process) and can communicate via shared objects. Process scheduling is priority driven, with preemptive time slicing (multitasking) within each priority level. Scheduling is implemented fully in Smalltalk (i.e. all algorithms are open and can be changed if there is a need to do so).
Each process has its own automatically growing stack which is protected against overflow. No stack size definition is needed at process creation time - the system will allocate additional stack memory in reasonable small increments. The algorithm is a so called "segmented spaghetti stack", consisiting of chains of stack segments. Stack overflow is signalled as an exception and can be cought (see ``Exceptions and Signals'') and handled gracefully. It is even possible to restart or continue with more stack space after such an exception.
Also, multiple processes can be debugged simulatiously (using the symbolic Debugger) - even while executing concurrently. This means, that other processes continue to execute while other processes may be debugged.
The windowing interface makes use of processes, by executing each toplevel view's application in a separate process (the so called "Windowgroup Process". This means, that other windows are not locked up by one window being debugged or busy (which would be the case in pure event driven systems).
The interesting classes are:
Process
represents a thread of control in Smalltalk.
An arbitrary number (limited by memory) of processes can execute concurrently
within the Smalltalk system.
These processes (also called threads or lightweight processes)
are not implemented as Unix/Windows processes,
but instead are created, managed and scheduled by Smalltalk itself.
They all run in within the same object (address-) space; therefore, the objects can be accessed by different processes.
Processes are scheduled and preemted by the ProcessorScheduler.
aBlock fork
aBlock forkNamed:aString
aBlock forkAt:priority
aBlock newProcess
aProcess priority
aProcess state
aProcess id
aProcess name
aProcess priority:newPriority
aProcess priorityRange:priorityInterval
aProcess suspend
aProcess resume
aProcess terminate
aProcess interruptWith:aBlock
Details are found in the
"Process
class documentation".
ProcessorScheduler
's sole instance (named Processor
)
is responsible for priority scheduling among running processes.
In contrast to other
Smalltalk and VM-based language implementations, scheduling is done completely at the Smalltalk language level.
This allows for different schedulers to be implemented if required.
The basic scheduling is preemptive priority based. Preemptive means that a process may be suspended and resumed at any time as determined by the runnable state of higher priority processes. No cooperation (explicit yield) is required to be programmed into the code to give up control.
Time slicing (multi tasking) is done by a high-prio timeslicer process, which assigns time slots within a priority group in a round robin fashion. Thus, other processes within that priority group are able to make progress, even if a single process performs a long running operation.
Typical messages sent to Processor
:
Processor activeProcess
Processor activePriority
Processor userSchedulingPriority
Processor userBackgroundPriority
Processor terminateActive
Processor yield
Processor suspend:aProcess
Processor resume:aProcess
More details are found in the
"ProcessorScheduler
class documentation".
Notice that a critical region semaphore may be only only entered once, even if the aquiring process already owns it. This may lead to deadlocks or difficult coding style if your code is recursive or is entering the critical region in multiple places. For that, a so called RecursionLock is provided. This behaves like a Semaphore, except for the re-entering situation. It allows for the one process which already owns the lock, to reenter a critical region.
Typical use:
Semaphore new
Semaphore forMutualExclusion
RecursionLock new
aSemaphore wait
aSemaphore waitWithTimeOut:seconds
aSemaphore signal
aSemaphore wouldBlock
aSemaphoreOrRecursionLock critical:[ ... criticalBlock ...]
Processor signal:aSemaphore onInput:fileDescriptor
Processor signal:aSemaphore onOutput:fileDescriptor
Processor signal:aSemaphore afterSeconds:numberOfSeconds
Delay
and ExternalStream
for portability.
SemaphoreSet
.
More details are found in the
"Semaphore
" or
"RecursionLock
"
class documentation.
Delay
wraps the above timer based suspend into a portable interface.
(Delay forSeconds:numberOfSeconds) wait
(Delay forMilliseconds:numberOfMilliseconds) wait
Delay waitForSeconds:numberOfSeconds
Delay waitForMilliseconds:numberOfMilliseconds
Delay waitUntil:aTimestamp
More details are found in the
"Delay
class documentation".
Copyright © 1996 Claus Gittinger Development & Consulting
<info@exept.de>