This is in answer to Mike's query of yesterday. Sorry it is
not threaded properly, but I'm using the mailing list instead
of reading news directly.
Hello again Mike,
>Thanks for your reply.
>
>It is agents that I am doing. I chose Pop-11 for my first agent program
>because it is quite an easy language, however, at the time I was unaware it
(snip)
>The only thing about changes made to the library is at the beginning of the
>HELP *ACTOR file:
(snip)
Ok, but bear in mind that Prof. Aaron Sloman has been working with
various people at Birmingham on agent stuff recently. He may very well
have, or know of, more recent libraries, either extending LIB ACTOR
or built separately. I'm sure he would already have answered you,
except that he told me he is away at a conference in Brussels until
Monday. (He'll probably answer when he gets back, knowing him.)
The following is an excerpt from a posting to pop-forum from around
the middle of April. I can't remember who I was replying to. (Me
marked by "*", mysterious stranger by "*>")
I'll explain it below the quote.
*>separate entity which served requests from the webserver. (Remind me: does
*>poplog make much use of multi-threading? Simple multi-threading extensions
*>would be a really neat addition if not.)
*
*Yes, I think we agree about this. It occurs to me that a CORBA compliant
*library should probably be added for this kind of purpose. And yes, poplog
*does allow a kind of multi-threading. As usual, the terminology is
*non-standard: in poplog threads are called processes. The only (potential)
*problem would be with the scheduling, since separate threads in poplog
*use co-operative multi-tasking, i.e. one thread explictly resumes
*another (using, strangely enough, a function called -resume- :-). I
*vaguely remember years ago (as an experiment) using a timer-interrupt
*routine to implement a kind of round-robin pre-emptive scheduling.
*Something
*like that would be a useful library for a server application. Note that
*we are talking about threads internal to poplog, not threads as provided
*by the OS.
*
*I don't know if the above is out of date: it is several years since I
*last used poplog (and I haven't installed Linux yet, which I was planning
*to do about a month ago, so can't yet install poplog. But Real Soon Now).
*
*Maybe there is now a library for pre-emptive scheduling of
*multiple (poplog) processes? It wouldn't be difficult: all you
*need is a list of which processes need to run in parallel, and
*a (timer driven) interrupt routine which switches between them.
*Of course, to be truly useful you then need to provide various
*other things ... (e.g. mutual exclusion around code segments, i.e.
*what the keyword "synchronized" is used for in Java.)
Poplog has, as you probably know, a mechanism called "processes". They
were called that when they were first implemented (by John Gibson). At
around that time, the usual terms were "co-routine" (already going
out of fashion), "lightweight process" (hence "process" for poplog)
or "thread" (coming into fashion). Nowadays, nearly everyone calls
them "threads". (For example, in Java they are called threads.)
The problem with poplog processes (i.e. threads) is that, like
the old Windows 3.1 and Macintosh operating systems, they use
what is called "co-operative multi-tasking" ("Task" is an even older
term for the same concept!!). Windows now, and unix always has, what
is called pre-emptive multi-tasking.
The difference is that, in co-operative multi-tasking, each thread
(or task, or process, or whatever you want to call it) keeps control
until it explicitly releases control. With pre-emptive multi-tasking,
the release of control is (also) caused by timer-interrupts. If it
is so simple, why isn't it added everywhere?
(a) I don't know. If it is not needed (see (b)) it would be easy to
turn off pre-emptive scheduling
(b) Pre-emptive scheduling is a huge source of bugs, deadlocks and
other Bad Things (see any book on parallel processing, operating
systems etc.) Code written for co-operative multi-tasking usually
won't work with pre-emptive multi-tasking when the different
threads access shared resources (the biggest problem on both the
Mac and Windows was output to the screen).
Lib Actor (this is what you are waiting to hear), being built on top
of Poplog processes, necessarily uses co-operative multi-tasking.
The difference from raw poplog processes is that, when a poplog
process gives up control, it specifies to which other process
control is transferred. (By RESUME, typically, or SUSPEND). In
Lib Actor, when an actor (process) gives up control, control is
transferred by default to the scheduler, which chooses which
process to run next.
How does an actor give up control?
By called WAIT(0).
Actor is based on the world's first object-oriented programming
language, which, as everyone should know, was called Simula 67.
(Jeers and heckling from the audience, who Know Better.) Simula
was inspired by various FORTRAN based simulation packages, but
they don't count. Simula is also a good name for a (female) android.
As a simulation language, processes waiting to run are kept in
a queue, and are run when either some event occurs, or after
a simulated delay. A call of WAIT(0) means to wait for zero
simulated time units. This might seem to do nothing, but in fact
the scheduler puts the current process behind all the other processes
which are waiting to run at the current simulated time. And then
runs the one at the front of the queue.
So, for implementing agents which are not interested in simulated
time delays, you run the whole "simulation" at one simulated
moment, which is NOW, which is time zero.
If you create three agents, A, B, and C (in that order) all ready
to run NOW, then the queue is
A B C
When you start the system, A starts running. If A calls WAIT(0),
the queue becomes
B C A
and B immediately starts running. The time is still NOW.
If you don't mind sprinkling calls of WAIT(0) throughout your
agent code (remember, they don't affect the behaviour of the
agent in any way) then I recommend you do it this way. The only
problem comes if one of your agents goes into an infinite loop
without calling WAIT(0) anywhere. Then none of the other agents
can run. (This is why Windows used to freeze so much.)
The reason I recommend this is that co-operative multi-tasking
is MUCH easier to debug, since it is deterministic. With pre-
emptive multi-tasking, the program never does the same thing
twice. So bugs can sometimes be virtually impossible to track
down. And pre-emptive multi-tasking doesn't even prevent
freezes: it is just that freezing is caused by deadlocks rather
than one process refusing to give up control. (Deadlocks are
again caused by the problem of accessing shared resources: the
solution, of making a thread wait its turn, gives rise to a
new problem, i.e. the possibility of two threads both waiting
for each other.)
For the same reason, I recommend that during development any
random numbers used are generated using fixed seeds, so that
you get the same sequence of random numbers (and therefore
the same program behaviour) each time.
If you do need to have pre-emptive multi-tasking, then the way
to do it is outlined in the quote near the top of this posting.
Lib Actor provies the scheduler and maintains the list of
processes ready to run. The timer interrupt simply calls
WAIT(0) on behalf of whichever agent/actor is currently
running.
Hope this helps.
Jonathan
|