[801] in Coldmud discussion meeting

root meeting help first first in chain previous in chain previous next next in chain last in chain last

Re: Multithreaded ColdC...

daemon@ATHENA.MIT.EDU (Sun Sep 10 16:03:37 1995 )

Date: Sun, 10 Sep 1995 15:58:30 -0400 (EDT)
From: James C Deikun <jcdst10+@pitt.edu>
To: 869683 Gillespie Brandon James <brandon@smithfield.declab.usu.edu>
Cc: coldstuff@MIT.EDU
In-Reply-To: <9509100226.AA02088@smithfield.declab.usu.edu>

On Sat, 9 Sep 1995, 869683 Gillespie Brandon James wrote:

> -----------------------------------------------------------------------
> ** Multithreaded ColdC **
> Modifies: pause()
> Changes:  *task* operators to *thread* operators (task_id() -> thread_id())

This seems gratuitously incompatible.

> Adds:     sync () {}, atomic {}, fork() and synchronized/atomic methods.
> * Overview
> A frame is the execution state of a ColdC method.  The current frame is
> only relative to the current method, beginning execution within a new
> frame uses a new frame context.  ColdC ticks are contained within each
> frame, rather than in a global context.  A thread is a stack of methods
> executing in relation to each other.

What if an atomic method called itself until about to run out of ticks, 
then returned, and did this to the maximum allowable recursion depth?  
This would be bad.  Sure there's a finite limit on how long this could 
occupy the machine, but it would probably be long enough to be infinite 
for all practical purposes.  Say the maximum is enough ticks for 100 
method calls per method (kinda low) and the max recursion depth is 10.  
That means 10^20 (100,000,000,000,000,000,000) method calls could be made 
in a row without letting any other task in.  Furthermore this increases 
exponentially with allowable recursion depth.

I never liked method-relative ticks much.

> * Outline
> Preemptive multi-threading will be based upon either CPU ticks or ColdC
> ticks (have not decided which).  CPU ticks give the advantage of also
> taking native functions into consideration, but cause tasks to be
> preempted faster on a loaded machine.

Well, that depends if your underlying system can give you CPU ticks for 
your task only rather than for the whole machine.

Are you doing your threading within the server code?  If so, I suggest 
not doing a context switch from a signal handler--this is messy and 
requires nonportable things like register dumps if you ever plan on 
adding GC.

> When a certain threshold has been reached, the task will be suspended
> and added to a list of preempted tasks, to continue execution at a later
> time.  Being preempted also refreshes the current frame's ticks.

Hm.  Will there be any provision for thread priorities?

> * Synchronizing
[*munch* --- so far so good]
> If a synchronize call is made, and the thread is unable to synchronize
> with the object, it may be blocked (if it is not atomic).  Blocked threads
> are suspended, and added to a list for that object.  When the
> current thread synchronizing to the object releases it's hold, the first
> thread in the blocked list is executed.  If a thread is blocked, and is
> atomic, the error ~blocked is thrown.

All right, so, how do you deal with a thread that synchronizes, say, on 
$sys, or your player database, and spins until the whole system goes *foop*?

And how do you deal with deadlock?

> * Atomic code blocks

Is there any good use for this, or is it just a quick compatibility fix?

> * Function pause()
> * Function fork() 
> fork() splits a thread.  When called it splits the thread into two exact
> frames.  The function fork() has a logical expression value of 0 to the
> child process, and the value is the forked thread id for the parent
> thread.

Which thread gets to stay synced on the objects the parent thread is 
synchronized on?  Can you wait for a child task to finish, and get some 
sorta results from it?  Can you fork from atomic code?  What happens if 
you wait for a child in atomic code?

> An optional delay argument may be supplied to fork, defaulting to 0.
> The delay specifies how long to wait before beginning execution of the
> child thread.
> Notes: possibly have a MAX_FORK for each thread; possibly have a method
> flag of 'fork', where if that method is called it starts its own
> execution thread, rather than becoming a part of the current thread.
> The logical expression value of a forked method is it's thread_id.

I like this idea.

Further considerations:

  What's with all these integer task_id()s?  Why not make a task a 
first-class object?

James "wants to be able to spork() a task" Deikun