[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

thread design



I'm at that stage where I'm ready to solicit outside input.  This is what I
have so far.  Question areas are maked with a ``###.''  A lot of this is
based on the CThreads package, because it's the only (real) threads package
I've ever used.  From what I hear, it's very similar to the Modula-3
threads interface.



Individual threads are represented by a thread structure.  The functions
for creating/manipulating threads are:

make-thread(function &key stack-size initially-suspended) => thread
    Creates a new thread that will initially call FUNCTION.

thread-self() => thread
    Return the thread object for the currently running thread.  ### Make
    this a special instead?

thread-yield()
    Inform the scheduler that now would be a good time to schedule someone
    else.

thread-exit(value) => nil
    Terminate the current thread.  Acts as if the initial function return
    returned with VALUE.  Unwind-protects *are* processed.
    ### Do we want to offer a facility to ignore unwind protects?

thread-exit-value(thread) => t
    Returns the value returned by the function supplied to MAKE-THREAD or
    the value supplied to THREAD-EXIT.  If the thread is still running,
    this blocks until it isn't.

thread-name(thread) => t <setfable>
    Allows the user to associate a name to a thread.  The name is not used
    by anything except the thread print function.

thread-plist(thread) => list <setfable>
    Allows the user to associate thread specific info to a thread.

thread-suspend(thread) => boolean
thread-restart(thread) => boolean
    Suspends (or restarts) the supplied thread.  ### Do we want to export
    this functionality?  Might be useful for trying to make advanced
    debugger interfaces to threads.

thread-kill(thread) => boolean
    Zot the thread.  ### what about unwind-protects?

thread-status(thread) =>
	(member :running :blocked :waiting :suspended :killed :exited)
    Returns the current status of thread:
	:running - self explanatory
	:blocked - blocked trying to lock a mutex.
	:waiting - waiting on a condition object.
	:suspended - hit with thread-suspend
	:killed - hit with thread-kill
	:exited - either called thread-exit or the initial function returned.

Note: CThreads has a function ``thread-detach'' that tells it not to bother
saving the return value for a thread.  We obviously don't need that,
because that is what the garbage collector is for.


Mutual exclusion is supported by mutex structures, which is a binary
semaphore. These are just like CThreads mutexes.

make-mutex(&optional name)
    Create a new (unlocked) mutext.  

mutex-name(mutex)
    Return (or set with setf) the name associated with this mutex.  Only
    used by the print-function.

mutex-lock(mutex)
    Attempt to lock the mutex, and block until you can.  Note: no attempt
    is made to protect against the case of a single thread attempting to
    lock a single mutex twice (which will deadlock it).

mutex-unlock(mutex)
    Unlock the mutex.  Note: no attempt is made to assure that the unlocked
    actually held the lock.

mutex-try-lock(mutex)
    Just like mutex-lock, but don't block.  Returns T if the lock was
    acquired, and NIL if not.

with-mutex ((mutex) &body body)
    Lock the mutex, execute the code in body, and then unlock the mutex.
    The unlock is in an unwind-protect.


Condition structures can be used to synchronize multiple threads.  Again,
these are just like the CThreads conditions.

make-condition(&optional name)
    Make a new condition object.

condition-name(condition)
    Return (or set) the associated name.  Again, only used by the print
    function.

condition-wait(condition mutex)
    Wait for some condition to arise.  The mutex is unlocked and the
    current thread is put in a :waiting state (this happens atomically).
    When the condition is signaled, attempt to re-acquire the lock on the
    mutex and return.  As some other thread might have beaten this thread
    to the lock, the condition should be verified again.  For example:

	(with-mutex (*mutex*)
	  (loop
            (if <some random condition protected by *mutex*>
		(return)
		(condition-wait *mutex* *condition*)))
	  <do stuff depending on this condition>)

with-condition((mutex condition-var) condition-form &body body)
    Syntactic sugar for the standard way to use conditions.  The above
    example becomes:

	(with-condition (*mutex* *condition*)
			<some random condition protected by *mutex*>
	  <do stuff depending on this condition>)

condition-signal(condition)
    Signal that the condition associated with CONDITION might have changed.
    This wakes up only one thread that is waiting on the condition.

condition-broadcast(condition)
    Same as condition-signal, but wake up all threads waiting on the
    condition.


Other models of parallelism and synchronization can easily be built on top
of these.  This set of primitives has been selected because other threads
packages seem to think that they are enough and that they all can be
efficiently implemented.

Comments?

-William