[MUD-Dev] Re: DevMUD: Inheritable modules
jwilson at rochester.rr.com
Sat Oct 31 08:09:53 New Zealand Daylight Time 1998
On Wed, 31 Dec 1969, Jon A. Lambert wrote:
>Why couldn't each module implement it's own desired level of
>threading. The loader would dynamically load the module and then
>start it running using a createthread(), startthread() mechanism.
>Each module then starts as a single thread. The module writer need
threads don't make sense for every module. Suppose I come up with
a fast_graphics module which simply exports a lot of functions? Moreover there
are other modules that will need many threads. I would prefer we take this on a
case-by-case basis; loading of the module should invoke some _init or DLLMain
function (this is how dlopen and Win32's LoadLibrary work), which, if the
module writer deems proper, can launch threads. The difference with what you
just said is that you are assuming that a module will always get a thread of
its own. I see that as a needless complication for simple modules.
>not even be concerned that they are threaded. Since there seems to be
>agreement that a common module interface is necessary, why not make
>that small bit of common inter-module interface code thread-safe by
>issuing the necessary locking mechanisms within the interface wrapper
this is not so straightforward. Avoiding deadlocks is a difficult science.
>ModuleA calls ModuleB wrapper ----> ModuleB function
>ModuleB calls ModuleA wrapper ----> ModuleA function
>All the code in the wrapper is fully reusable, generic and
>threadsafe. It just contains bindings (data) for the module
>it is attached to. Creation of wrappers could even be
>automated. It might also be useful to require the loaded
>module to use a standard function name (i.e. init()) so
>we can have a handle to start a thread on. And perhaps
>a kill() or stop() handle.
if there is a mutex on each of Module A's functions such that only one
thread may be in a function at once, there will be a TON of needless locking
(you don't need to lock atoi(), but you do need to lock strtok(), for instance).
Moreover you will have deadlocks galore, as functions try to call one another
but have to block on a mutex.
>The base loader could:
>A module wrapper's data portion might contain a simple message
>queue and handled as such. Thus a module could call
>the wrapper function receive_message() which pops() the wrapper
>queue and causes one of the modules routines to be executed.
>The return of the function would of course occur in the wrapper
>and any return value is sent_back to the caller via a wrapper
>function send_message(). Note that the owning threads during
>function calls will be the called module's. So single-threaded
>modules can interface easily with multi-threaded modules.
I have a number of problems with this.
a. the module abstraction is not necessarily isomorphic to an
independent thread receiving and emitting asynchronous messages. In
particular, a module may not NEED to serialize access to everything inside it -
some functions may be totally reentrant, some data structures would be better
served by monitors, some functions may be independent of one another and not
need to be serialized.
b. message-passing raises a whole host of programming issues. Nicholas
suggested this at one point, and I won't reiterate my position, except to say
that message-passing will NOT be simple and understandable to module writers.
int what = foo () makes sense to 100% of or target audience. the cruft needed
to send a message, then wait for THE RIGHT MESSAGE to return (as opposed to
messages from other modules that you didn't know were about to send you
messages) is hard.
c. it's hard to avoid deadlocks. A sends a request to B and waits for
the reply, but B is waiting for a request from C who is waiting for A. Do you
block in the wrapper and wait for them to return? Or do you make the programmer
filter received messages manually? See b. for that option.
More information about the MUD-Dev