Object » Link » Process
A process represents an independent path of control in the system. This path of control may be stopped (by sending the message suspend) in such a way that it can later be restarted (by sending the message resume). When any one of several paths of control can be advanced, the single instance of ProcessorScheduler named Processor determines which one will actually be advanced.
Process is a subclass of Link. It is therefore possible to queue processes in a LinkedList as well as in a Semaphore.
A process lives in the Smalltalk image; it is not mapped to a process of your computer's operating system. It is not possible to associate a process with one of serveral processors of a multi-processor system.
Upon termination, a process unwinds its stack and evaluates the blocks of all ensure: and ifCurtailed: messages.
suspendedContext - BlockContext
???
priority - Integer
The process priority
myList - nil or LinkedList (for a ready process) or Semaphore (for a waiting process)
for a waiting process, this variable references the queue that contains the process. For a process that is
neither ready nor blocked, this instance variable is nil.
errorHandler - Block
This variable is currently not used.
This feature was used earlier versions of Squeak that did not support
exception handling. With the introduction of exception handling this
variable is not needed anymore. (Have at look at Squeak 2.3 to see how
this variable was used.)
name - String
an optional process name. Processes are not required to have a name and most processes
do not have one.
A process is always created from a block. The convenient shorthand to create a process is to send one of the messages fork, forkAt: to a block. These messages create a process that is immediately scheduled.
To simply create a new process and to obtain a reference to the new process, one sends the message newProcess to a block that is evaluated without arguments. To create a process from a block that is evaluated with arguments, one sends the message newProcessWith:.
fork
create and answer a ready process with the priority of the currently active
process.
forkAndWait
Suspend the current process and execute the receiver in a new process.
Wait until the new process terminates and resume the suspended process.
forkAt: priority
create and answer a ready process with the given priority.
forkAt: priority named: name
create and answer a ready process with the given priority and name.
forkNamed: name
create and answer a named ready process with the priority of the currently active
process.
newProcess
create and answer a suspended process with the priority of the currently active
prcoess. The statements of the new process are:
newProcessWith: arrayOfArguments
create and answer a suspended process with the priority of the currently active
process.
A process is always in one of these five states:
Suspended
This is the state of a process that is not registered
for execution, but can be resumed at any time.
Ready
This is the state of a process is registered for execution. A ready
process may become the active process. Ready processes are queued in
the queues of the ProcessorScheduler.
Active
This is the state of the currently executed process. There is always
exactly one active process.
Blocked
This is the state of a process that is registered in the queue of
a Semaphore that has no excess signals.
A process that is waiting at a semaphore becomes ready when the message
signal is sent to that semaphore.
Terminated
This is the state of a process that has irrevocably finished execution.
A terminated process can not be put into a different state.
Two very different situations cause a process to terminate:
Process termination is a complicated operation that can include the finalization of blocks that are protected with either an ensure: or an ifCurtailed: block. A good understanding of process termination is required to avoid errors that are later difficult to find. Termination includes these steps:
Termination of a process that is queued as either ready or blocked begins with the removal of the process from the queue. This is necessary to avoid activation or continuation of the process to be terminated.
The call stack is unwound and all pending ensure: and ifCurtailed: blocks are evaluated.
ensure: and ifCurtailed: blocks are meant for cleanup operations. These blocks should have robust exception handling; ideally, they should catch all exceptions. It is recommended to avoid statements that could suspend process termination.
reader := [ | stream | stream := [FileStream readOnlyFileNamed: <filename>] on: Error do: [:exception | exception return: nil]. stream notNil ifTrue: [[self processStream: stream] ensure: [stream close]. ]. ].
This example has both robust exception handling and termination-safe cleanup.
Here is an example for process termination:
| sema process | sema := Semaphore new. process := [ [sema wait.] ensure: [Transcript show: 'process is terminated'; cr] ] newProcess. process priority: Processor timingPriority; resume. Transcript show: 'queue length = ', sema size printString; cr. process terminate. Transcript show: 'queue length = ', sema size printString; cr. sema inspect.
The process process is given the highest priority; after resumption it runs until it enqueues itself into the queue of the semaphore. When this happened, the user interface process becomes active again and terminates the waiting process. During termination a message is written in the transcript window. Two additional transcript messages show that process termination removes a waiting process from the queue of the semaphore. The final inspect allows you to convince yourself that the semaphore is in fact left with an empty queue.