Previous
Contents
Next

Advanced Programming Techniques for MVC

Use of Processes


The process framework of Smalltalk includes these classes:

Of these, Process, Semaphore and ProcessorScheduler are the most elementary definitions. Classes Delay, Monitor and SharedQueue are defined in terms of these most elementary classes.

Most Smalltalk developers do not use processes at all. When processes are used, their use is often motivated by the desire to execute some time-consuming piece of code in the background. In Smalltalk-80, processes were used for event-driven simulation and this is still an important domain of process use.


Is is often desired to do time-consuming things in the background, that is, in a way that permits the user to continue his work. A well-known example is the loading of a huge file. To load a file, you use code like this:

 | stream newLineChar line |
stream := FileStream readOnlyFileNamed: 'TreeView4.1.cs'.
newLineChar := Character cr.

[stream atEnd]
  whileFalse:
    [line := stream upTo: newLineChar.
     Transcript show: '.'.
    ].
stream close.

This is very simple, but for the time the file is read the user interface does not respond to user input, which is sometimes an annoyance.

To read the file in a background process, you can do this: (Do not forget to replace the file name (displayed in bold-face types) with the name of an existing file before you try this.)

reader := 
[  | stream newLineChar line |
 stream := FileStream readOnlyFileNamed: 'TreeView4.1.cs'.
 newLineChar := Character cr.

 [stream atEnd]
   whileFalse:
     [line := stream upTo: newLineChar.
      Transcript show: '.'.
     ].
 stream close.
].

reader forkAt: Processor userBackgroundPriority.

Explanations

  1. To create a process, you have to encapsulate the code in a block.
  2. To start the process, you send that block one of the messages fork or forkAt:
  3. forkAt: allows you to assign a process priority, which normally desired. The instance protocol of class ProcessorScheduler contains methods to obtain process priorities (in message category 'priority names'). Processor is the sole instance of ProcessorScheduler in your image, so you can obtain process priorities from that object.
  4. Processor userBackgroundPriority is a good choice for file handling in the background.

Important Note: It is not allowed to use a return-statement (that is, a statement of the form "^<expression>") in a block that you use to create a process.

When you try that example with the name of a file that does not exist, you will experience something very unpleasant:
The forked process will bring up an error notifier and this will seriously damage the behavior of the user interface. When this happens you should quit Squeak without saving the image.

To avoid problems of that kind, a block that is designed to be forked should always have a robust error handling.

reader := 
[  | stream newLineChar line |
 stream := 
   [FileStream readOnlyFileNamed: 'ming.1.cs']
       on: Error
       do: [:exception | exception return: nil].
 stream notNil
   ifTrue:
     [newLineChar := Character cr.

      [stream atEnd]
         whileFalse:
            [line := stream upTo: newLineChar.
             Transcript show: '.'.
            ].
      stream close.
     ].
].

reader forkAt: Processor userBackgroundPriority.

This is safe code. It will never bring up a notifier and it will simply terminate when the creation of the file stream fails for whatever reason.

A process terminates after it has executed its last statement. However, a process can also be forcibly terminated by another process. Upon termination, a process unwinds its call stack and evaluates all unwind blocks. To close a file stream under all circumstances one should write:

reader := 
[  | stream newLineChar line |
 stream := 
   [FileStream readOnlyFileNamed: 'ming.1.cs']
       on: Error
       do: [:exception | exception return: nil].
 stream notNil
   ifTrue:
     [newLineChar := Character cr.

      [[stream atEnd]
         whileFalse:
            [line := stream upTo: newLineChar.
             Transcript show: '.'.
            ]
      ]
      ensure: [stream close].
     ].
].

reader forkAt: Processor userBackgroundPriority.

Previous
Contents
Next