Multithreading

John M McIntosh johnmci at smalltalkconsulting.com
Mon Mar 28 08:14:03 UTC 2005


I'll comment on how the current implementation works, hah I hope I get  
most of it correct. I know other on the list are actually responsible  
for it's creation.
If you load the vmmaker squeak map package you will find.

Interpreter>>transferTo: aProc

Is the method that actually transfer control between active process to  
another, outside of direct control of any Smalltalk code.

This method is called via
Interpreter>>primitiveSuspend
Interpreter>>primitiveWait
Interpreter>>primitiveYield
Interpreter>>resume:

On Wait and Yield we add the current process to the end of a linked  
list based on it's priority, then we wake the first runnable process  
based on looking from highest to lowest priority.
If there is no runnable process the VM will quit, with  'scheduler  
could not find a runnable process', readers of the list are welcome to  
read the list archives to find the change set I managed to get into the  
update stream which led to that condition for the first few early  
adopters one weekend many years ago.

For Resume: we put the active process to sleep and run the indicated  
process if the indicated process has a higher priority.

Suspend is used mostly in the interface by the debugger and  
ProcessBrower to control the runability of an indicated process.

This algorithm ensures:
a) high priority processes will run first.
b) all process at a given priority level will run in round robin  
fashion if process switching occurs.


When a process is resumed depends on what it is doing. It could be  
waiting on a semaphore, or on a delay. Because of how resume: works a  
process can become runnable but not run if a higher priority task can  
run. This means of course a higher priority process that does not yield  
control it will block runnable lower priority processes, or processes  
at the same priority.

But if for example you have a server application that accepts incoming  
requests then forks off work at a lower priority this allows the   
higher priority listeners to
accept work, then lower priority tasks perform the actual work, but are  
prevented from blocking higher priority process from accepting work. I  
think someone earlier
commented on forking work at the user background priority to prevent  
the UI from locking up.

In general most usages of yield I have seen are in endless while loops  
where one polls for work churning CPU cycles as a side effect and  
without the yield blocking any other runable processes. For the most  
part usage of yield in the image follow this pattern.

"In Theory" there is nothing to prevent you from creating a processor  
scheduler that wakes up every N milli-seconds and decides to suspend or  
change the priority of the running process and picking a different  
process to resume. There would be some question if this is 'safe',   
however I do recall in VisualWorks at some point there was an optional  
changeset to provide this functionality.  'Safe' here means when does a  
process lose control and what does that mean for multi-threading. That  
I can't answer, mind if someone could point to a Use case that would be  
a plausible failure condition that would be interesting.

When processing switching can occur is of course a question to ask.  
This occurs.
when a method send is made or
when a long unconditionalJump bytecode is executed in the backwards  
direction. > 9 bytecodes?
on a primitive call if  when the call takes > 1 or perhaps 17ms  
depending on platform.

The checks are in  Interpreter>>checkForInterrupts

I'll note we don't attempt to make decisions every time we encounter  
these three conditions, rather we attempt to limit our checking every  
2-3 milliseconds with some other
decision making to ensure we make the objective of giving Delay  
accuracy a ms or less degree of error. This routine does things like  
check for the low space, finalization, polling, interrupt key semaphore  
and attempt to wake the waiting processes semaphores if required.   
Usually one of the three conditions above occur within a 1 ms  
timeframe.

I will note because Morphic polls for user UI events every 20 or so  
milliseconds at a high priority, this ensures if you run things below  
Processor lowIOPriority that a keyboard interrupt will be serviced,  
this enables the stopping of most runaway processes.

Killing runaway process that have consumed all the existing memory is  
another issue for another day, those become unkillable because the VM  
can't service enough bytecodes fast enough to trigger the debugger.


On Mar 27, 2005, at 9:05 PM, Daniel Salama wrote:

> Ross,
>
> I asked myself the same questions. As I am new to Smalltalk, one of  
> the things that attracted me to Smalltalk was that it's been around  
> for so many decades. I would have assumed that this "limitation" in  
> its libraries (or image(s)) as far as concurrency would have been  
> resolved by now. I guess I got spoiled with some of the facilities  
> available in Java.
>
> Yielding control to other processes without any guarantees that  
> control will come back in a correspondingly mutual manner makes me  
> just want to not even try developing anything multi-threaded friendly.
>
> As far as Seaside behavior in, I posted a similar question in  
> Seaside's list  
> (http://lists.squeakfoundation.org/pipermail/seaside/2005-March/ 
> 004685.html) but didn't really get an answer for it. I thank Avi for  
> letting me know that Transcript>>show is just about the worst thing I  
> could use to show status progress but no one really addressed my  
> question about Seaside/Squeak/GOODS performance (even though it's all  
> relative to application needs and application design).
>
> Thanks,
> Daniel
>
> On Mar 27, 2005, at 9:44 PM, Ross Boylan wrote:
>
>> This has been a very interesting thread for me.  I thought squeak did
>> time-slicing.  Are other smalltalks the same in not doing timeslicing?
>>
>> On Sat, Mar 26, 2005 at 08:50:46AM -0800, Tim Rowledge wrote:
>>> Daniel Salama <dsalama at user.net> wrote:
>>>
>>>> Karl,
>>>>
>>>> The problem I encountered is that while this method was executing,
>>>> Squeak was completely unresponsive. I could not open the Process
>>>> Browser, I could not do anything whatsoever in Squeak.
>>> Of course it was; there should be no surprise there at all. There is  
>>> a
>>> single active process and it runs until it stops. You can make it  
>>> stop
>>> temporarily by deliberately yielding occasioanlly which will give
>>
>> What actions, or types of actions, are necessary to yield control?
>>
>>> other processes a chance to hog the cpu for themselves - but if that
>>> other process doesn't play nice and yield occasionally you will still
>>> feel locked out.
>>>
>>> There is not any round-robin or timeslicing scheduling done by  
>>> default.
>>> You can implement it fairly simply (google is your friend and can  
>>> find
>>> many news postings on the subject over many years) if you really need
>>> it. The potential danger with using such a modifed scheduling setup  
>>> is
>>> that most of the image is not multi-thread safe.
>>
>> Sounds as if it would take a big overhaul to get reliable
>> multi-threading.
>>
>>>
>>>
>>> tim
>>
>> I had understood that squeak was being used (via seaside) for web
>> servers.  How do they manage to deal with processing many things at
>> once (I'm assuming they do)?
>>
>> Ross Boylan
>>
>>
>
>
>
--
======================================================================== 
===
John M. McIntosh <johnmci at smalltalkconsulting.com> 1-800-477-2659
Corporate Smalltalk Consulting Ltd.  http://www.smalltalkconsulting.com
======================================================================== 
===




More information about the Squeak-dev mailing list