Semaphores
MUSHCode for Semaphores
Topic: Semaphores
Author: Javelin
Summary: MUSH 101's first guest lecture. Javelin walks through SEMAPHORE.
Log file from MUSH101
Classroom 1102
A chalkboard fills one wall, with an old beat-up lectern in front of
it. The other three walls are painted off-white. Several chairs with attached
desktop-like surfaces (standard classroom chairs) are scattered about in no
particular order.
Contents:
Rhysem
Grinna
Yosh
Hephtur
Vedui
Lianne
Halatir
Javelin
Gothuga
Obvious exits:
Out <O>
Trispis walks to the front of the classroom and begins speaking in a dry
monotone, "Welcome to MUSH 101's third code class. We'll be starting
momentarily. If you haven't read the 'rules', please do so now (type: rules).
Our featured speaker is Javelin of M*U*S*H, current maintainer of PennMUSH.
His topic for today is semaphores. Please enjoy the class."
Online classrooms are difficult to present. Since the entire class
will be text-based, any excessive chatter can quickly become annoying. So,
please observe the following courtesies for both your instructor and your
fellow student.
1. The instructor is in charge of the classroom for the duration of his/her
presentation. This authority extends to the +code channel as well. The only
people above him in authority are admins and wizards, but their job is simply
to enforce the instructor's authority.
2. If you have a question, pose a question mark (?) on the +code channel (to
join this channel, type: @chan/on code). You will be allowed to ask your
question when called upon (it's a good idea to have paper and pencil for
writing down questions, as it may be several minutes before you are allowed to
ask).
3. We want the class to be fun and interesting, but excessive horseplay
(wise-cracking and the like) is disruptive to those who are here to learn.
Please direct horseplay and joking to the +pub&grille channel (so people can
turn it off, if they wish).
Trispis dances a little jig, after his speech, and turns the lecturn over to
Javelin, "Take it away, Meistro." (:
Javelin chuckles.
Javelin says, "Ok, let's start with a problem."
Javelin drops Race Condition.
Javelin points to "Race Condition". Examine that object, if you please. :)
Race Condition(#1904V)
Type: Thing Flags: VISUAL
Owner: Javelin Zone: *NOTHING* Credits: 1
Parent: *NOTHING*
Powers:
Warnings checked: none
Created: Sat Feb 14 20:08:19 1998
Last Modification: Sat Feb 14 20:10:13 1998
VA [#1649]: Javelin
FLIP2 [#1649]: @emit The winner is %va!
FLIP [#1649]: $flip: @va me=%N; @tr me/flip2
Home: Javelin's Room(#XXXXRn)
Location: Classroom 1102(#236R)
Javelin says, "Here's a simple object. You type 'flip', and it tells you that
you win."
Javelin types flip
The winner is Javelin!
The winner is Yosh!
The winner is Trispis!
The winner is Halatir! <--+-- Note these two lines.
The winner is Halatir! <--'
The winner is Gothuga!
Javelin giggles. "Now, perhaps we just saw the problem with this object."
Javelin says, "If A has just typed 'flip', and B types 'flip' right after, VA
may get set to B's name *before* FLIP2 is run for A."
Javelin says, "As a result, we'll see "The winner is B!" twice, instead of
"The winner is A!" followed by "The winner is B!""
Javelin says, "Does everybody understand the problem?"
Yosh nods
Gothuga nods
Trispis nods.
Lianne nods
Halatir nods.
Rhysem nods
Grinna nods
Vedui *8)s.
Javelin says, "Ok. This problem is called a 'race condition' -- because if
people are racing to run the command, it can get mixed. Semaphores are a
coding concept that offer us a fix for this. Let's look at a partial fix
first."
Javelin drops Partial Fix.
Javelin suggests: ex partial fix
Partial Fix(#1909Vn)
Type: Thing Flags: VISUAL NO_COMMAND
Owner: Javelin Zone: *NOTHING* Credits: 1
Parent: *NOTHING*
Powers:
Warnings checked: none
Created: Sat Feb 14 22:07:59 1998
Last Modification: Sat Feb 14 22:08:26 1998
FLIP2 [#1649]: @emit The winner is %va!
FLIP [#1649]: $spin: @wait me={@va me=%N; @tr me/flip2}
Home: Javelin's Room(#XXXXRn)
Location: Classroom 1102(#236R)
Sat Feb 14 22:09:34 1998
Javelin says, "What's new here? We've added '@wait me=' in front of the list
of commands run by the FLIP attribute."
Javelin says, "Instead of immediately executing those two commands, the object
will 'wait' for a signal to do so."
Javelin says, "Examine partial fix again."
Partial Fix(#1909V)
Type: Thing Flags: VISUAL
Owner: Javelin Zone: *NOTHING* Credits: 1
Parent: *NOTHING*
Powers:
Warnings checked: none
Created: Sat Feb 14 22:07:59 1998
Last Modification: Sat Feb 14 22:10:49 1998
SEMAPHORE [#1+i]: 2
FLIP2 [#1649]: @emit The winner is %va!
FLIP [#1649]: $spin: @wait me={@va me=%N; @tr me/flip2}
Home: Javelin's Room(#XXXXRn)
Location: Classroom 1102(#236R)
Javelin says, "You'll see that there's a new atttribute, called SEMAPHORE,
which shows how many of those signals the object is waiting on."
Javelin says, "We can see that two people have already typed 'spin'."
Javelin says, "When an object is waiting on a semaphore like this, the @notify
command is used to send a single signal (say that 3 times fast!)."
Javelin says, "I'll type: @notify partial fix"
The winner is Trispis!
Trispis woohoos! (:
<Pub&Grille> q:*D Halatir hrms. ;)
<Pub&Grille> Trispis says, "Not bad for a wizard who's half asleep. (:"
Javelin says, "When the object is @notified, the SEMAPHORE attribute is
reduced by 1, and the commands that the object was waiting to execute are
executed."
Javelin does a couple more notifies.
The winner is Yosh!
The winner is Gothuga!
<Code> Trispis says, "?"
<Code> Trispis notes his own question.
Javelin says, "There are only 3 things you can do involving semaphores: @wait
on a semaphore, @notify a sempahore, and, finally @drain a semaphore. @drain
removes the commands that are waiting without executing them."
Javelin drains fix.
Javelin says, "If you ex fix now, the SEMAPHORE attribute is gone."
Partial Fix(#1909V)
Type: Thing Flags: VISUAL
Owner: Javelin Zone: *NOTHING* Credits: 1
Parent: *NOTHING*
Powers:
Warnings checked: none
Created: Sat Feb 14 22:07:59 1998
Last Modification: Sat Feb 14 22:14:24 1998
VA [#1649]: Gothuga
FLIP2 [#1649]: @emit The winner is %va!
FLIP [#1649]: $spin: @wait me={@va me=%N; @tr me/flip2}
Home: Javelin's Room(#XXXXRn)
Location: Classroom 1102(#236R)
Javelin says, "Ok, everybody set a semaphore on themselves, using this
command: @wait me=think notified!"
Javelin says, "When you've done that, type @ps"
Queue for : Trispis
Player Queue:
Object Queue:
Wait Queue:
Semaphore Queue:
[#4]Trispis(#4POUWnACMc):think notified!
------------ Queue Done ------------
Totals: Player...0/0[0del] Object...0/0[0del] Wait...0/3 Semaphore...1/8
Javelin says, "Notice how your Semaphore Queue now shows the command that you
have waiting on yourself."
Javelin says, "When you've seen that, @notify or @drain yourself."
Notified.
notified!
<Pub&Grille> q:*D Mewis says, "notified!"
Javelin says, "Are there any questions so far?"
Trispis nods. Only one, so far. You ready?
Javelin says, "Yep."
Trispis says, "Are all activations of the $command placed into ordered @waits
(in the holding queue, or whatever)? Like 'Trispis, Gothuga, Halatir, etc'...
were they all being held in stasis somewhere?"
Javelin says, "Correct. TO see this, try something like this:
@dol 1 2 3=@wait me=think ##"
Javelin says, "Then type @ps"
Queue for : Trispis
Player Queue:
Object Queue:
Wait Queue:
Semaphore Queue:
[#4]Trispis(#4POUWnACMc):think 1
[#4]Trispis(#4POUWnACMc):think 2
[#4]Trispis(#4POUWnACMc):think 3
------------ Queue Done ------------
Totals: Player...0/0[0del] Object...0/0[0del] Wait...0/3 Semaphore...3/16
Notified.
1
Notified.
2
Notified.
3
Sat Feb 14 22:19:37 1998
Javelin says, "You should see 3 commands on your semaphore queue. If you use
@notify/all me, they'll all be run, in order"
Trispis says, "Ah. Okay. Cool. (:"
<Code> Trispis says, "?"
<Code> Javelin says, "Yeah, Tris?"
<Code> Trispis has a followup to his earlier question (and your example)... Is
there a way to limit the number of semaphores permitted (like no more than 2,
then that @dol 1 2 3 would get curtailed after 2)?
<Code> Javelin says, "Nope, afraid not."
Javelin says, "Ok, now there's one very neat thing about semaphores I haven't
mentioned."
Javelin says, "Everybody @drain yourself, and then type @notify me"
Drained.
Notified.
Javelin says, "Then ex me/SEMAPHORE"
SEMAPHORE [#1+i]: -1
Javelin says, "You'll see that you have a *negative* semaphore count, because
you've notified yourself when you didn't have any command waiting."
Javelin says, "What's so great about a negative semaphore? Well, a -1
semaphore means that the next time you @wait on yourself, you'll execute the
command *immediately*, and your semaphore count will go back to 0. This is the
basis of the solution to our race condition."
Javelin drops Semaphore Solution.
Javelin suggests: ex solution
Semaphore Solution(#1905Vz)
Type: Thing Flags: VISUAL STARTUP
Owner: Javelin Zone: *NOTHING* Credits: 1
Parent: *NOTHING*
Powers:
Warnings checked: none
Created: Sat Feb 14 20:08:28 1998
Last Modification: Sat Feb 14 22:17:36 1998
STARTUP [#1649$]: @drain me; @notify me
SEMAPHORE [#1+i]: -1
FLIP2 [#1649]: @emit The winner is %va!; @notify me
FLIP [#1649]: $toss: @wait me={@va me=%N; @tr me/flip2}
Home: Javelin's Room(#XXXXRn)
Location: Classroom 1102(#236R)
The winner is Trispis!
The winner is Gothuga!
The winner is Yosh!
The winner is Mewis!
Javelin says, "When someone types 'toss', what happens? The @va me and @tr run
immediately, because there's a negative semaphore. If someone else tries to
type toss right afterward, *their* command gets put on the semaphore queue,
and isn't run until, at the end of the first command, the @notify me is run."
Javelin says, "This is the basic way to use sempahores to enforce a single
user finishing their command before anybody else's gets in the way --
(1) @notify the object so it's get a -1 semaphore,
(2) put the commands on the semaphore queue with an @wait, and
(3) At the end of the set of commands to be run, call @notify to bring the
semaphore count back down."
Javelin says, "A fancy term for this is 'mutual exclusion' or 'mutex'. I think
the help file may use this term somewhere."
Javelin says, "The reason the @startup is there, btw, is in case the MUSH is
shut down in the middle of some command on the semaphore. When it starts back
up, we want to be sure the SEMAPHORE count on that object is exactly -1, so we
@drain it, and then @notify it once."
<Code> Trispis suddenly has ideas for his elevator. (:
<Code> Javelin nodnods. :) A hard thing, though, is getting the elevator to be
willing to stop on, say, floor 2, when it's on the way from 3 to 1, but not be
willing to stop at floor 4. Proof left to the reader.
<Code> Trispis nods.
Javelin says, "Let me stop here for a sec and see if there are any questions
about how the solution object works, or anything else I've said so far?"
<Code> Trispis offers a simple example to see if he understands... check my
thinking, please Jav...
<Code> Javelin nods.
<Code> Trispis says, "I've got a vending machine of some sort (let's call it a
coffee pot)..."
<Code> Trispis says, "I wanna have it do a series of emits (%N picks up the
hot glass coffee pot. *wait* %N pours the hot black liquid into a styrofoam
cup. *wait* %N places the pot back on the warmer.)."
<Code> Trispis says, "I'd put the @wait at the beginning of the $command...
trigger the various @emits with normal @waits (with seconds or watever)...
then, after the last one, I'd do a @notify <pot>."
<Code> Trispis says, "That way only one person can pour a cup of java at a
time?"
<Code> Javelin says, "That would work fine, yes."
Philip ?
Javelin says, "Go ahead, Philip."
Philip thinks he's answered his own question, but, how would you set it up so
that there was only one winner? take the @notify out from the end?
Javelin says, "That's a little trickier, since you can only drain *all* of the
semaphores off, not just some of them. You'd have to do something like decided
randomly if this person was going to displace the current winner, and if so,
@drain the object and set up the @wait for the new winner."
Javelin says, "That's a sort of different problem. :)"
Philip says, "Sorry, came into the middle. =)"
[Trispis inserts an observation about Philip's question. My interpretation of
Philip's 'problem' (i.e., only having one winner <period>) would occur in a
situation where there is actually a race (as in a MUSH scavenger hunt, for
example). Having a -1 SEMAPHORE... and then NOT @notifying the object would
result in an 'only one winner' situation (all others would be accumulated as
'to be queued' SEMAPHORES, which could all be @drained ). Also, if this is the
desired result (only one winner), then it's probably a good idea to @halt the
object after it has completed its processing of the "one winner", rather than
accumulate SEMAPHORES (unless you're wanting to record 'second place', 'third
place', etc).]
Javelin says, "Historically, semaphores came about because there was often
code that should only be used by one player at a time. Some post office
systems were notably like this."
Javelin says, "Does anyone happen to know how they used to force code to only
be useable by one player at a time in the days before semaphores?"
Javelin is about to show his age. :)
Trispis speculates a @set %@=no_command, then reset it afterwards.
Javelin says, "Anybody? Anybody? Bueller? (Nope, Tris, this was before the
NO_COMMAND flag, too.)"
Javelin says, "Although that's a pretty clever thought. :)"
Vedui recalls the @force stuff I think..unless it wasn't used on belgariad.
Trispis imagines it's pretty hairy, then.
Javelin tells ya. "They used to code objects so they only worked if a player
was holding them."
<Pub&Grille> Trispis says, "Hot potato. (:"
Javelin says, "Since only one player can hold an object at once, that enforced
mutual exclusion."
Philip says, "You could probably do it by setting an attribute in the
beginning indicating that the thing was in use, and then resetting it at the
end... doesn't remember the commands that were used though."
Vedui was thinking of something else then :P
Trispis says, "that's simpler than what was going through my mind. (:"
Gothuga hrmmms, "Couldn't anyone just take the objects and not put them back
down then Jav?
Javelin points to his nose and indicates Gothuga approvingly. "And *that* is
the $64k question"
Gothuga cheers..
Javelin says, "Consider this object"
Javelin drops Two-step.
Two-step(#685z)
Type: Thing Flags: STARTUP
Owner: Javelin Zone: *NOTHING* Credits: 1
Parent: *NOTHING*
Powers:
Warnings checked: none
Created: Sat Feb 14 22:30:42 1998
Last Modification: Sat Feb 14 22:35:17 1998
STARTUP [#1649$]: @drain me; @notify me
SEMAPHORE [#1+i]: -2
STEP2 [#1649]: $step2: @switch %#=[v(DOER)], {"%N did step two. We're done.;
&DOER me; @notify me}, {"Sorry, %N --
[switch(hasattr(me,DOER),1,[name(v(DOER))] is using me.,do step 1 first)]}
STEP1 [#1649]: $step1: @wait me={"%N did step one.; &DOER me=%#}
Home: Javelin's Room(#XXXXRn)
Location: Classroom 1102(#236R)
Javelin suggests: examine two-step
Two-step says, "Sorry, Yosh -- do step 1 first"
Two-step says, "Yosh did step one."
Two-step says, "Yosh did step two. We're done."
Javelin says, "The idea of 'two-step' is that you want someone to type two
commands, step1 and step2. Until that person types 'step2', you don't want
anybody else to use the object."
Two-step says, "Lianne did step one."
Two-step says, "Sorry, Halatir -- Lianne is using me."
Two-step says, "Lianne did step two. We're done."
Two-step says, "Halatir did step one."
Two-step says, "Halatir did step two. We're done."
Trispis grins. Cool. (:
Javelin says, "But there's a problem."
Javelin says, "And it's Gothuga's problem."
Javelin says, "What if someone does step1, and then disconnects?"
Javelin says, "The object becomes deadlocked -- nobody can use it right."
Philip suggests using Ahear?
Javelin says, "That's one solution, Philip -- listen for someone leaving,
disconnecting, etc. But someone could still be in the room and just forget to
do step2."
Two-step says, "Trispis did step one."
Trispis grins evilly and refuses to do step2. (:<
Two-step says, "Sorry, Lianne -- Trispis is using me."
Javelin says, "This is why we have 'timed semaphores'"
Javelin says, "A 'timed semaphore' is just like a normal semaphore, but if
it's not drained or notified within a certain time, it gets automatically
notified."
<Pub&Grille> Trispis says, "No drinking coffee straight from the pot!!!"
Javelin says, "The command is: @wait me/10=think I'm notified."
Javelin says, "Where 10 is the number of seconds. If you run that command, and
don't @notify me within 10 seconds, you'll get notified anyway."
I'm notified.
Javelin says, "Let me give you an example of how I once used timed semaphores
to solve a fairly ugly problem like this."
Javelin says, "I wanted to design a soft-coded combat system that worked like
this:"
Javelin says, "Attacker would select a type of attack (kick, punch, or slap)"
Javelin says, "Defender would select a type of defense (dodge, block, or
parry)"
Javelin says, "And the combat system would look up the result in a big matrix.
For example, a parry was ineffective against a kick, etc."
Javelin says, "There were 2 immediate problems: (1) how to remember what the
attacker's attack type was and who they attacked until the defender responded,
and (2) what to do if the defender lagged a lot or lost their connection."
Javelin says, "Both were solved by having the combat system set a timed
semaphore *on the defender*. The defense commands (dodge, block, parry),
basically @notified the defender's semaphore which caused the result of the
fight to be computed. But if the defender didn't respond within 5 seconds, the
semaphore automatically notified (and the defender, by default, 'dodged')."
Javelin notes that this is not a perfect solution, as the defender can defend
attacks amazingly well by simply @draining him/herself. :) Ah well. :)
Trispis says, "or by doing nothing?"
Javelin says, "No, doing nothing causes the semaphore to time out, and thus be
notified. If you did nothing, you 'dodged'."
Javelin says, "A timed semaphore that times out is *notified*, not *drained*.
That's important."
Vedui snaps his fingers! why didntcha say so when we used the combat system...
@drain woulda killed all my enemies ;)
Gothuga chuckles..
Javelin points to Vedui, a long-suffering guinea pig of that particular combat
system, as a matter of fact.
Javelin says, "Ok, I'm just about done. There's only one more thing I want to
mention, and then we can move to questions/discussion if any."
Trispis doesn't see how it would have killed them. maybe I'm missing
something.
Javelin says, "It wouldn't have killed them, Tris. If you @drained yourself,
it would have erased the fact that you were attacked, is all."
Trispis says, "Ah. Okay... allowing you to attack back?"
Javelin nods to Tris.
Gothuga says, "Letting you attack without being attacked, right?"
Trispis grins. Devious. (:
Gothuga says, "Isn't that CS still up on the PennMUSH FTP Site?"
Javelin nods, it's called NCS 1.0 or something, Gothuga.
Javelin says, "The final little tidbit is this."
Javelin says, "Remember that if you're using a -1 semaphore, you want to
@notify at the end of a command sequence."
Javelin says, "If the command sequence includes an @switch, you must put an
@notify into every branch of the switch."
Javelin says, "But if the command sequence ends in an @dolist, you've got a
problem."
Javelin says, "You can't do: @dol a b c = whatever; @notify me"
Javelin says, "Because the @notify will run *before* the 'whatever' is
finished running."
Trispis hrms....
Javelin says, "(because @dol adds the 3 whatevers back onto the queue, after
the @notify)"
Sat Feb 14 22:59:49 1998
Javelin says, "This is why, as you can see in 'help @dolist', there's a
/notify switch to @dolist."
@DOLIST
@dolist[/notify] <list> = <action>
@dolist executes the <action> for each element in <list>. If <list> is a
function, it will be evaluated to obtain the necessary list to use. It
may be any space-separated list of strings, which can be object numbers,
attributes, or arbitary words.
<action> is a command or list of commands enclosed in braces { }
and is performed once for every item in <list>. The special symbol "##"
is replaced by the corresponding item from <list>. The special symbol
"#@" is replaced by the position of that item in the list.
If the /notify switch is used, a "@notify me" is queued after all the
list commands. This is useful for object synchronization with semaphores.
Example: @dolist [lcon(here)] = "[name(##)]
would cause you to say the name of all objects in the room.
Javelin says, "@dolist/notify a b c=whatever will do the whatever for a, b,
and c, and *then* do an @notify."
Javelin says, "It will only @notify the object that's running the @dolist, but
usually, that's the right object."
Javelin hopes he said that fairly clearly. To take the corresponding case with
@switch, this is bad:
@sw a=f1, {whatever1}, {whatever2}; @notify me
Javelin says, "This is good:
@sw a=f1, {whatever1; @notify me}, {whatever2; @notify me}
"
Javelin knows there's a lot of misunderstanding about the queue, so if you
have questions, now's a good time. :)
Trispis ?
Trispis asks his question...
Javelin nods.
Trispis says, "I know that there are times when semi-colon separated @commands
are placed sequentially in the queue... and other times when they're not (as
in the case of the @dol 1 2 3 ; @notify me)... Is there a rule of thumb for
determining how things turn out?"
Javelin says, "Yes. Understand this and you become a guru. :)"
Javelin says, "When an object runs commands on one of its attributes (due to
being triggered by a $command, let's say...)"
Javelin says, "All of the commands in that attribute are put onto the queue,
one immediately after the other, in the order they appear."
Javelin says, "That is, if the commands are: @va me=hi; @vb me=[get(me/va)],
you can be sure that VB will contain 'hi' one this is run. Nothing can come
between them, and nothing can put them out of order."
Trispis nods.
Javelin says, "Some commands explicitly place other command-list onto the
queue, at the end of whatever's currently there. These include @force,
@trigger, @switch, and @dolist (and @wait 0=command-list)"
Javelin says, "So, if the trigger command-list is:
@va me=hi; @dol a b c=@vb me=##; @vb me=[get(me/va)]; @emit %vb
... the queue starts out holding all those commands, in order. The @va is run,
and VA is set to hi. Then the @dol is run, and three @VB commands are added to
the back of the queue. The queue now looks like this:
@vb me=[get(me/va)]; @emit %vb; @vb me=a; @vb me=b; @vb me=c
...We keep going, VB gets set to "hi", "hi" gets emitted, and then VB gets set
to "a", to "b", and to "c", and we're done."
Javelin says, "Similarly, consider
@emit hi; @sw k=f1, {a1}, {b1}; @emit bye
The queue starts like that, we emit hi, we decide whether a1 or b1 should be
added to the back of the queue. The queue now looks like this:
@emit bye; a1 (or b1)
...We emit bye, and then we run a1 or b1. If we wanted the emit of bye to be
at the end of everything, we must either do this:
@sw k=f1, {a1; @emit bye}, {b1; @emit bye}
...Or force the @emit to be cued late:
@sw k=f1, {a1}, {b1}; @wait 0=@emit bye
...Or use a semaphore;
@sw k=f1, {a1; @notify me}, {b1; @notify me}; @wait me=@emit byte
...etc."
Javelin says, "This is why a lot of people have given up on this and try to
use side-effection functions and avoid @switch entirely (about which I have
mixed feelings. :)"
Javelin whews. Hope that helps. Any other questions?
Trispis looks around.
Vedui says, "?"
Javelin nods to Ved.
Vedui :) When ya @dol and @sel and all, and it considers the placement on "da
queue", does it do that in consideration with other commands running as well,
by other objects?
Trispis smiles.
Vedui says, "Ie... in your example above, if ya had 100 obj's doing that the
same time, would it be a queue which could look different each time depending
on timing of individual commands in that split second, or would it be "nicely"
queued? :)"
Javelin says, "Well, the queued commands go onto the back of the queue. Since
we're already on whatever part of the queue is running the object's commands,
in general, they should be queued right after the ones we're running. MUSH
isn't really multitasking, after all -- it's a serial system. However, there
are a couple of oddities...
First, the "wait queue" (commands set with @wait <seconds>=<command-list>) is
kept separate, and those commands are inserted onto the main queue when it's
their time.
Second, stuff typed by players directly into the MUSH gets bumped to the front
of the queue. That's why, for example, if your +who is coded using @dolist,
you can get paged and have it interrupt in the middle."
The good reasons for that are:
1. it makes the MUSH feel more responsive to players, and
2. It lets @halt have nice high precedence so you can stop a runaway object!)"
Javelin says, "But if everything is object code, then everything started by a
single attribute on an object should run to the end without any other object
getting in the way."
Javelin says, "Anybody else?"
Vedui says, "The problem I run into is that I @sel to ensure a command is only
run once. ie, check for a counter .. "@sel v(counter)=1,fail,&counter me=1" ..
.. and if ya spam it enuf, it'll still run the command multiple times, simply
since it seems to run a second command before the first even has time to set
the counter to 1."
Javelin says, "Yes, this can happen. This is when you want a -1 semaphore. :)"
Trispis says, "mutex"
Vedui says, "which would suggest the queue isn't orderly lined up ;)"
Trispis says, "Who's spamming this? Players?"
Vedui says, "Yep :)"
Javelin says, "No, the problem is that those commands are being run 'as if'
from a player socket, because they're triggered by directly typed commands."
Vedui says, "ohh..."
Trispis nods. That's why you need the -1 semaphore (player actions get bumped
to the front of the queue).
Javelin says, "So, second @sel gets queued up ahead of the counter
incrementing."
Vedui says, "I thought the queue was arranged after the object, not that it
was the triggering player who'd triggered it. Ick :) that'd do it yeah."
Javelin looks around for a stack of "Queue Guru" buttons for the participants.
:)
Trispis grins at Jav, I'll leave an edited WHO (no sites) in the log. (:
Sat Feb 14 23:29:58 1998
Vedui says, "Eh Jav, ya always want contributions to the God Manual.. how
about putting in a section of how the queue works? ;)"
Vedui says, "unless ya already did and I just aint read it recently enuf ;)"
Javelin says, "Good idea. You can write one now and send it to me. :)"
Vedui bleahs. Sure... as soon as I finish half of my other work ;)
Trispis says, "I'll have this log ready tomorrow... you can copy/paste the
queue portion over to the manual. (:"
Vedui looks at his calendar, "is next year okay? ;)"
Javelin knows how you feel. :) "Well, I guess we'll finish here. Thanks for
coming."
Vedui applauds
Vedui *8)
Trispis applauds also and walks once again to the front of the room.
Trispis shakes Javelin's hand (sorry for the powerplay) and says, "Class
dismissed. Thanks for attending. The log will be available at
ftp://mush101.pennmush.org/mush101/ClassLogs ... tomorrow afternoon."
Javelin takes Two-step.
Javelin takes Race Condition.
Javelin takes Semaphore Solution.
Javelin takes Partial Fix.
Trispis stops logging.
Author: Javelin
Summary: MUSH 101's first guest lecture. Javelin walks through SEMAPHORE.
Log file from MUSH101
Classroom 1102
A chalkboard fills one wall, with an old beat-up lectern in front of
it. The other three walls are painted off-white. Several chairs with attached
desktop-like surfaces (standard classroom chairs) are scattered about in no
particular order.
Contents:
Rhysem
Grinna
Yosh
Hephtur
Vedui
Lianne
Halatir
Javelin
Gothuga
Obvious exits:
Out <O>
Trispis walks to the front of the classroom and begins speaking in a dry
monotone, "Welcome to MUSH 101's third code class. We'll be starting
momentarily. If you haven't read the 'rules', please do so now (type: rules).
Our featured speaker is Javelin of M*U*S*H, current maintainer of PennMUSH.
His topic for today is semaphores. Please enjoy the class."
Online classrooms are difficult to present. Since the entire class
will be text-based, any excessive chatter can quickly become annoying. So,
please observe the following courtesies for both your instructor and your
fellow student.
1. The instructor is in charge of the classroom for the duration of his/her
presentation. This authority extends to the +code channel as well. The only
people above him in authority are admins and wizards, but their job is simply
to enforce the instructor's authority.
2. If you have a question, pose a question mark (?) on the +code channel (to
join this channel, type: @chan/on code). You will be allowed to ask your
question when called upon (it's a good idea to have paper and pencil for
writing down questions, as it may be several minutes before you are allowed to
ask).
3. We want the class to be fun and interesting, but excessive horseplay
(wise-cracking and the like) is disruptive to those who are here to learn.
Please direct horseplay and joking to the +pub&grille channel (so people can
turn it off, if they wish).
Trispis dances a little jig, after his speech, and turns the lecturn over to
Javelin, "Take it away, Meistro." (:
Javelin chuckles.
Javelin says, "Ok, let's start with a problem."
Javelin drops Race Condition.
Javelin points to "Race Condition". Examine that object, if you please. :)
Race Condition(#1904V)
Type: Thing Flags: VISUAL
Owner: Javelin Zone: *NOTHING* Credits: 1
Parent: *NOTHING*
Powers:
Warnings checked: none
Created: Sat Feb 14 20:08:19 1998
Last Modification: Sat Feb 14 20:10:13 1998
VA [#1649]: Javelin
FLIP2 [#1649]: @emit The winner is %va!
FLIP [#1649]: $flip: @va me=%N; @tr me/flip2
Home: Javelin's Room(#XXXXRn)
Location: Classroom 1102(#236R)
Javelin says, "Here's a simple object. You type 'flip', and it tells you that
you win."
Javelin types flip
The winner is Javelin!
The winner is Yosh!
The winner is Trispis!
The winner is Halatir! <--+-- Note these two lines.
The winner is Halatir! <--'
The winner is Gothuga!
Javelin giggles. "Now, perhaps we just saw the problem with this object."
Javelin says, "If A has just typed 'flip', and B types 'flip' right after, VA
may get set to B's name *before* FLIP2 is run for A."
Javelin says, "As a result, we'll see "The winner is B!" twice, instead of
"The winner is A!" followed by "The winner is B!""
Javelin says, "Does everybody understand the problem?"
Yosh nods
Gothuga nods
Trispis nods.
Lianne nods
Halatir nods.
Rhysem nods
Grinna nods
Vedui *8)s.
Javelin says, "Ok. This problem is called a 'race condition' -- because if
people are racing to run the command, it can get mixed. Semaphores are a
coding concept that offer us a fix for this. Let's look at a partial fix
first."
Javelin drops Partial Fix.
Javelin suggests: ex partial fix
Partial Fix(#1909Vn)
Type: Thing Flags: VISUAL NO_COMMAND
Owner: Javelin Zone: *NOTHING* Credits: 1
Parent: *NOTHING*
Powers:
Warnings checked: none
Created: Sat Feb 14 22:07:59 1998
Last Modification: Sat Feb 14 22:08:26 1998
FLIP2 [#1649]: @emit The winner is %va!
FLIP [#1649]: $spin: @wait me={@va me=%N; @tr me/flip2}
Home: Javelin's Room(#XXXXRn)
Location: Classroom 1102(#236R)
Sat Feb 14 22:09:34 1998
Javelin says, "What's new here? We've added '@wait me=' in front of the list
of commands run by the FLIP attribute."
Javelin says, "Instead of immediately executing those two commands, the object
will 'wait' for a signal to do so."
Javelin says, "Examine partial fix again."
Partial Fix(#1909V)
Type: Thing Flags: VISUAL
Owner: Javelin Zone: *NOTHING* Credits: 1
Parent: *NOTHING*
Powers:
Warnings checked: none
Created: Sat Feb 14 22:07:59 1998
Last Modification: Sat Feb 14 22:10:49 1998
SEMAPHORE [#1+i]: 2
FLIP2 [#1649]: @emit The winner is %va!
FLIP [#1649]: $spin: @wait me={@va me=%N; @tr me/flip2}
Home: Javelin's Room(#XXXXRn)
Location: Classroom 1102(#236R)
Javelin says, "You'll see that there's a new atttribute, called SEMAPHORE,
which shows how many of those signals the object is waiting on."
Javelin says, "We can see that two people have already typed 'spin'."
Javelin says, "When an object is waiting on a semaphore like this, the @notify
command is used to send a single signal (say that 3 times fast!)."
Javelin says, "I'll type: @notify partial fix"
The winner is Trispis!
Trispis woohoos! (:
<Pub&Grille> q:*D Halatir hrms. ;)
<Pub&Grille> Trispis says, "Not bad for a wizard who's half asleep. (:"
Javelin says, "When the object is @notified, the SEMAPHORE attribute is
reduced by 1, and the commands that the object was waiting to execute are
executed."
Javelin does a couple more notifies.
The winner is Yosh!
The winner is Gothuga!
<Code> Trispis says, "?"
<Code> Trispis notes his own question.
Javelin says, "There are only 3 things you can do involving semaphores: @wait
on a semaphore, @notify a sempahore, and, finally @drain a semaphore. @drain
removes the commands that are waiting without executing them."
Javelin drains fix.
Javelin says, "If you ex fix now, the SEMAPHORE attribute is gone."
Partial Fix(#1909V)
Type: Thing Flags: VISUAL
Owner: Javelin Zone: *NOTHING* Credits: 1
Parent: *NOTHING*
Powers:
Warnings checked: none
Created: Sat Feb 14 22:07:59 1998
Last Modification: Sat Feb 14 22:14:24 1998
VA [#1649]: Gothuga
FLIP2 [#1649]: @emit The winner is %va!
FLIP [#1649]: $spin: @wait me={@va me=%N; @tr me/flip2}
Home: Javelin's Room(#XXXXRn)
Location: Classroom 1102(#236R)
Javelin says, "Ok, everybody set a semaphore on themselves, using this
command: @wait me=think notified!"
Javelin says, "When you've done that, type @ps"
Queue for : Trispis
Player Queue:
Object Queue:
Wait Queue:
Semaphore Queue:
[#4]Trispis(#4POUWnACMc):think notified!
------------ Queue Done ------------
Totals: Player...0/0[0del] Object...0/0[0del] Wait...0/3 Semaphore...1/8
Javelin says, "Notice how your Semaphore Queue now shows the command that you
have waiting on yourself."
Javelin says, "When you've seen that, @notify or @drain yourself."
Notified.
notified!
<Pub&Grille> q:*D Mewis says, "notified!"
Javelin says, "Are there any questions so far?"
Trispis nods. Only one, so far. You ready?
Javelin says, "Yep."
Trispis says, "Are all activations of the $command placed into ordered @waits
(in the holding queue, or whatever)? Like 'Trispis, Gothuga, Halatir, etc'...
were they all being held in stasis somewhere?"
Javelin says, "Correct. TO see this, try something like this:
@dol 1 2 3=@wait me=think ##"
Javelin says, "Then type @ps"
Queue for : Trispis
Player Queue:
Object Queue:
Wait Queue:
Semaphore Queue:
[#4]Trispis(#4POUWnACMc):think 1
[#4]Trispis(#4POUWnACMc):think 2
[#4]Trispis(#4POUWnACMc):think 3
------------ Queue Done ------------
Totals: Player...0/0[0del] Object...0/0[0del] Wait...0/3 Semaphore...3/16
Notified.
1
Notified.
2
Notified.
3
Sat Feb 14 22:19:37 1998
Javelin says, "You should see 3 commands on your semaphore queue. If you use
@notify/all me, they'll all be run, in order"
Trispis says, "Ah. Okay. Cool. (:"
<Code> Trispis says, "?"
<Code> Javelin says, "Yeah, Tris?"
<Code> Trispis has a followup to his earlier question (and your example)... Is
there a way to limit the number of semaphores permitted (like no more than 2,
then that @dol 1 2 3 would get curtailed after 2)?
<Code> Javelin says, "Nope, afraid not."
Javelin says, "Ok, now there's one very neat thing about semaphores I haven't
mentioned."
Javelin says, "Everybody @drain yourself, and then type @notify me"
Drained.
Notified.
Javelin says, "Then ex me/SEMAPHORE"
SEMAPHORE [#1+i]: -1
Javelin says, "You'll see that you have a *negative* semaphore count, because
you've notified yourself when you didn't have any command waiting."
Javelin says, "What's so great about a negative semaphore? Well, a -1
semaphore means that the next time you @wait on yourself, you'll execute the
command *immediately*, and your semaphore count will go back to 0. This is the
basis of the solution to our race condition."
Javelin drops Semaphore Solution.
Javelin suggests: ex solution
Semaphore Solution(#1905Vz)
Type: Thing Flags: VISUAL STARTUP
Owner: Javelin Zone: *NOTHING* Credits: 1
Parent: *NOTHING*
Powers:
Warnings checked: none
Created: Sat Feb 14 20:08:28 1998
Last Modification: Sat Feb 14 22:17:36 1998
STARTUP [#1649$]: @drain me; @notify me
SEMAPHORE [#1+i]: -1
FLIP2 [#1649]: @emit The winner is %va!; @notify me
FLIP [#1649]: $toss: @wait me={@va me=%N; @tr me/flip2}
Home: Javelin's Room(#XXXXRn)
Location: Classroom 1102(#236R)
The winner is Trispis!
The winner is Gothuga!
The winner is Yosh!
The winner is Mewis!
Javelin says, "When someone types 'toss', what happens? The @va me and @tr run
immediately, because there's a negative semaphore. If someone else tries to
type toss right afterward, *their* command gets put on the semaphore queue,
and isn't run until, at the end of the first command, the @notify me is run."
Javelin says, "This is the basic way to use sempahores to enforce a single
user finishing their command before anybody else's gets in the way --
(1) @notify the object so it's get a -1 semaphore,
(2) put the commands on the semaphore queue with an @wait, and
(3) At the end of the set of commands to be run, call @notify to bring the
semaphore count back down."
Javelin says, "A fancy term for this is 'mutual exclusion' or 'mutex'. I think
the help file may use this term somewhere."
Javelin says, "The reason the @startup is there, btw, is in case the MUSH is
shut down in the middle of some command on the semaphore. When it starts back
up, we want to be sure the SEMAPHORE count on that object is exactly -1, so we
@drain it, and then @notify it once."
<Code> Trispis suddenly has ideas for his elevator. (:
<Code> Javelin nodnods. :) A hard thing, though, is getting the elevator to be
willing to stop on, say, floor 2, when it's on the way from 3 to 1, but not be
willing to stop at floor 4. Proof left to the reader.
<Code> Trispis nods.
Javelin says, "Let me stop here for a sec and see if there are any questions
about how the solution object works, or anything else I've said so far?"
<Code> Trispis offers a simple example to see if he understands... check my
thinking, please Jav...
<Code> Javelin nods.
<Code> Trispis says, "I've got a vending machine of some sort (let's call it a
coffee pot)..."
<Code> Trispis says, "I wanna have it do a series of emits (%N picks up the
hot glass coffee pot. *wait* %N pours the hot black liquid into a styrofoam
cup. *wait* %N places the pot back on the warmer.)."
<Code> Trispis says, "I'd put the @wait at the beginning of the $command...
trigger the various @emits with normal @waits (with seconds or watever)...
then, after the last one, I'd do a @notify <pot>."
<Code> Trispis says, "That way only one person can pour a cup of java at a
time?"
<Code> Javelin says, "That would work fine, yes."
Philip ?
Javelin says, "Go ahead, Philip."
Philip thinks he's answered his own question, but, how would you set it up so
that there was only one winner? take the @notify out from the end?
Javelin says, "That's a little trickier, since you can only drain *all* of the
semaphores off, not just some of them. You'd have to do something like decided
randomly if this person was going to displace the current winner, and if so,
@drain the object and set up the @wait for the new winner."
Javelin says, "That's a sort of different problem. :)"
Philip says, "Sorry, came into the middle. =)"
[Trispis inserts an observation about Philip's question. My interpretation of
Philip's 'problem' (i.e., only having one winner <period>) would occur in a
situation where there is actually a race (as in a MUSH scavenger hunt, for
example). Having a -1 SEMAPHORE... and then NOT @notifying the object would
result in an 'only one winner' situation (all others would be accumulated as
'to be queued' SEMAPHORES, which could all be @drained ). Also, if this is the
desired result (only one winner), then it's probably a good idea to @halt the
object after it has completed its processing of the "one winner", rather than
accumulate SEMAPHORES (unless you're wanting to record 'second place', 'third
place', etc).]
Javelin says, "Historically, semaphores came about because there was often
code that should only be used by one player at a time. Some post office
systems were notably like this."
Javelin says, "Does anyone happen to know how they used to force code to only
be useable by one player at a time in the days before semaphores?"
Javelin is about to show his age. :)
Trispis speculates a @set %@=no_command, then reset it afterwards.
Javelin says, "Anybody? Anybody? Bueller? (Nope, Tris, this was before the
NO_COMMAND flag, too.)"
Javelin says, "Although that's a pretty clever thought. :)"
Vedui recalls the @force stuff I think..unless it wasn't used on belgariad.
Trispis imagines it's pretty hairy, then.
Javelin tells ya. "They used to code objects so they only worked if a player
was holding them."
<Pub&Grille> Trispis says, "Hot potato. (:"
Javelin says, "Since only one player can hold an object at once, that enforced
mutual exclusion."
Philip says, "You could probably do it by setting an attribute in the
beginning indicating that the thing was in use, and then resetting it at the
end... doesn't remember the commands that were used though."
Vedui was thinking of something else then :P
Trispis says, "that's simpler than what was going through my mind. (:"
Gothuga hrmmms, "Couldn't anyone just take the objects and not put them back
down then Jav?
Javelin points to his nose and indicates Gothuga approvingly. "And *that* is
the $64k question"
Gothuga cheers..
Javelin says, "Consider this object"
Javelin drops Two-step.
Two-step(#685z)
Type: Thing Flags: STARTUP
Owner: Javelin Zone: *NOTHING* Credits: 1
Parent: *NOTHING*
Powers:
Warnings checked: none
Created: Sat Feb 14 22:30:42 1998
Last Modification: Sat Feb 14 22:35:17 1998
STARTUP [#1649$]: @drain me; @notify me
SEMAPHORE [#1+i]: -2
STEP2 [#1649]: $step2: @switch %#=[v(DOER)], {"%N did step two. We're done.;
&DOER me; @notify me}, {"Sorry, %N --
[switch(hasattr(me,DOER),1,[name(v(DOER))] is using me.,do step 1 first)]}
STEP1 [#1649]: $step1: @wait me={"%N did step one.; &DOER me=%#}
Home: Javelin's Room(#XXXXRn)
Location: Classroom 1102(#236R)
Javelin suggests: examine two-step
Two-step says, "Sorry, Yosh -- do step 1 first"
Two-step says, "Yosh did step one."
Two-step says, "Yosh did step two. We're done."
Javelin says, "The idea of 'two-step' is that you want someone to type two
commands, step1 and step2. Until that person types 'step2', you don't want
anybody else to use the object."
Two-step says, "Lianne did step one."
Two-step says, "Sorry, Halatir -- Lianne is using me."
Two-step says, "Lianne did step two. We're done."
Two-step says, "Halatir did step one."
Two-step says, "Halatir did step two. We're done."
Trispis grins. Cool. (:
Javelin says, "But there's a problem."
Javelin says, "And it's Gothuga's problem."
Javelin says, "What if someone does step1, and then disconnects?"
Javelin says, "The object becomes deadlocked -- nobody can use it right."
Philip suggests using Ahear?
Javelin says, "That's one solution, Philip -- listen for someone leaving,
disconnecting, etc. But someone could still be in the room and just forget to
do step2."
Two-step says, "Trispis did step one."
Trispis grins evilly and refuses to do step2. (:<
Two-step says, "Sorry, Lianne -- Trispis is using me."
Javelin says, "This is why we have 'timed semaphores'"
Javelin says, "A 'timed semaphore' is just like a normal semaphore, but if
it's not drained or notified within a certain time, it gets automatically
notified."
<Pub&Grille> Trispis says, "No drinking coffee straight from the pot!!!"
Javelin says, "The command is: @wait me/10=think I'm notified."
Javelin says, "Where 10 is the number of seconds. If you run that command, and
don't @notify me within 10 seconds, you'll get notified anyway."
I'm notified.
Javelin says, "Let me give you an example of how I once used timed semaphores
to solve a fairly ugly problem like this."
Javelin says, "I wanted to design a soft-coded combat system that worked like
this:"
Javelin says, "Attacker would select a type of attack (kick, punch, or slap)"
Javelin says, "Defender would select a type of defense (dodge, block, or
parry)"
Javelin says, "And the combat system would look up the result in a big matrix.
For example, a parry was ineffective against a kick, etc."
Javelin says, "There were 2 immediate problems: (1) how to remember what the
attacker's attack type was and who they attacked until the defender responded,
and (2) what to do if the defender lagged a lot or lost their connection."
Javelin says, "Both were solved by having the combat system set a timed
semaphore *on the defender*. The defense commands (dodge, block, parry),
basically @notified the defender's semaphore which caused the result of the
fight to be computed. But if the defender didn't respond within 5 seconds, the
semaphore automatically notified (and the defender, by default, 'dodged')."
Javelin notes that this is not a perfect solution, as the defender can defend
attacks amazingly well by simply @draining him/herself. :) Ah well. :)
Trispis says, "or by doing nothing?"
Javelin says, "No, doing nothing causes the semaphore to time out, and thus be
notified. If you did nothing, you 'dodged'."
Javelin says, "A timed semaphore that times out is *notified*, not *drained*.
That's important."
Vedui snaps his fingers! why didntcha say so when we used the combat system...
@drain woulda killed all my enemies ;)
Gothuga chuckles..
Javelin points to Vedui, a long-suffering guinea pig of that particular combat
system, as a matter of fact.
Javelin says, "Ok, I'm just about done. There's only one more thing I want to
mention, and then we can move to questions/discussion if any."
Trispis doesn't see how it would have killed them. maybe I'm missing
something.
Javelin says, "It wouldn't have killed them, Tris. If you @drained yourself,
it would have erased the fact that you were attacked, is all."
Trispis says, "Ah. Okay... allowing you to attack back?"
Javelin nods to Tris.
Gothuga says, "Letting you attack without being attacked, right?"
Trispis grins. Devious. (:
Gothuga says, "Isn't that CS still up on the PennMUSH FTP Site?"
Javelin nods, it's called NCS 1.0 or something, Gothuga.
Javelin says, "The final little tidbit is this."
Javelin says, "Remember that if you're using a -1 semaphore, you want to
@notify at the end of a command sequence."
Javelin says, "If the command sequence includes an @switch, you must put an
@notify into every branch of the switch."
Javelin says, "But if the command sequence ends in an @dolist, you've got a
problem."
Javelin says, "You can't do: @dol a b c = whatever; @notify me"
Javelin says, "Because the @notify will run *before* the 'whatever' is
finished running."
Trispis hrms....
Javelin says, "(because @dol adds the 3 whatevers back onto the queue, after
the @notify)"
Sat Feb 14 22:59:49 1998
Javelin says, "This is why, as you can see in 'help @dolist', there's a
/notify switch to @dolist."
@DOLIST
@dolist[/notify] <list> = <action>
@dolist executes the <action> for each element in <list>. If <list> is a
function, it will be evaluated to obtain the necessary list to use. It
may be any space-separated list of strings, which can be object numbers,
attributes, or arbitary words.
<action> is a command or list of commands enclosed in braces { }
and is performed once for every item in <list>. The special symbol "##"
is replaced by the corresponding item from <list>. The special symbol
"#@" is replaced by the position of that item in the list.
If the /notify switch is used, a "@notify me" is queued after all the
list commands. This is useful for object synchronization with semaphores.
Example: @dolist [lcon(here)] = "[name(##)]
would cause you to say the name of all objects in the room.
Javelin says, "@dolist/notify a b c=whatever will do the whatever for a, b,
and c, and *then* do an @notify."
Javelin says, "It will only @notify the object that's running the @dolist, but
usually, that's the right object."
Javelin hopes he said that fairly clearly. To take the corresponding case with
@switch, this is bad:
@sw a=f1, {whatever1}, {whatever2}; @notify me
Javelin says, "This is good:
@sw a=f1, {whatever1; @notify me}, {whatever2; @notify me}
"
Javelin knows there's a lot of misunderstanding about the queue, so if you
have questions, now's a good time. :)
Trispis ?
Trispis asks his question...
Javelin nods.
Trispis says, "I know that there are times when semi-colon separated @commands
are placed sequentially in the queue... and other times when they're not (as
in the case of the @dol 1 2 3 ; @notify me)... Is there a rule of thumb for
determining how things turn out?"
Javelin says, "Yes. Understand this and you become a guru. :)"
Javelin says, "When an object runs commands on one of its attributes (due to
being triggered by a $command, let's say...)"
Javelin says, "All of the commands in that attribute are put onto the queue,
one immediately after the other, in the order they appear."
Javelin says, "That is, if the commands are: @va me=hi; @vb me=[get(me/va)],
you can be sure that VB will contain 'hi' one this is run. Nothing can come
between them, and nothing can put them out of order."
Trispis nods.
Javelin says, "Some commands explicitly place other command-list onto the
queue, at the end of whatever's currently there. These include @force,
@trigger, @switch, and @dolist (and @wait 0=command-list)"
Javelin says, "So, if the trigger command-list is:
@va me=hi; @dol a b c=@vb me=##; @vb me=[get(me/va)]; @emit %vb
... the queue starts out holding all those commands, in order. The @va is run,
and VA is set to hi. Then the @dol is run, and three @VB commands are added to
the back of the queue. The queue now looks like this:
@vb me=[get(me/va)]; @emit %vb; @vb me=a; @vb me=b; @vb me=c
...We keep going, VB gets set to "hi", "hi" gets emitted, and then VB gets set
to "a", to "b", and to "c", and we're done."
Javelin says, "Similarly, consider
@emit hi; @sw k=f1, {a1}, {b1}; @emit bye
The queue starts like that, we emit hi, we decide whether a1 or b1 should be
added to the back of the queue. The queue now looks like this:
@emit bye; a1 (or b1)
...We emit bye, and then we run a1 or b1. If we wanted the emit of bye to be
at the end of everything, we must either do this:
@sw k=f1, {a1; @emit bye}, {b1; @emit bye}
...Or force the @emit to be cued late:
@sw k=f1, {a1}, {b1}; @wait 0=@emit bye
...Or use a semaphore;
@sw k=f1, {a1; @notify me}, {b1; @notify me}; @wait me=@emit byte
...etc."
Javelin says, "This is why a lot of people have given up on this and try to
use side-effection functions and avoid @switch entirely (about which I have
mixed feelings. :)"
Javelin whews. Hope that helps. Any other questions?
Trispis looks around.
Vedui says, "?"
Javelin nods to Ved.
Vedui :) When ya @dol and @sel and all, and it considers the placement on "da
queue", does it do that in consideration with other commands running as well,
by other objects?
Trispis smiles.
Vedui says, "Ie... in your example above, if ya had 100 obj's doing that the
same time, would it be a queue which could look different each time depending
on timing of individual commands in that split second, or would it be "nicely"
queued? :)"
Javelin says, "Well, the queued commands go onto the back of the queue. Since
we're already on whatever part of the queue is running the object's commands,
in general, they should be queued right after the ones we're running. MUSH
isn't really multitasking, after all -- it's a serial system. However, there
are a couple of oddities...
First, the "wait queue" (commands set with @wait <seconds>=<command-list>) is
kept separate, and those commands are inserted onto the main queue when it's
their time.
Second, stuff typed by players directly into the MUSH gets bumped to the front
of the queue. That's why, for example, if your +who is coded using @dolist,
you can get paged and have it interrupt in the middle."
The good reasons for that are:
1. it makes the MUSH feel more responsive to players, and
2. It lets @halt have nice high precedence so you can stop a runaway object!)"
Javelin says, "But if everything is object code, then everything started by a
single attribute on an object should run to the end without any other object
getting in the way."
Javelin says, "Anybody else?"
Vedui says, "The problem I run into is that I @sel to ensure a command is only
run once. ie, check for a counter .. "@sel v(counter)=1,fail,&counter me=1" ..
.. and if ya spam it enuf, it'll still run the command multiple times, simply
since it seems to run a second command before the first even has time to set
the counter to 1."
Javelin says, "Yes, this can happen. This is when you want a -1 semaphore. :)"
Trispis says, "mutex"
Vedui says, "which would suggest the queue isn't orderly lined up ;)"
Trispis says, "Who's spamming this? Players?"
Vedui says, "Yep :)"
Javelin says, "No, the problem is that those commands are being run 'as if'
from a player socket, because they're triggered by directly typed commands."
Vedui says, "ohh..."
Trispis nods. That's why you need the -1 semaphore (player actions get bumped
to the front of the queue).
Javelin says, "So, second @sel gets queued up ahead of the counter
incrementing."
Vedui says, "I thought the queue was arranged after the object, not that it
was the triggering player who'd triggered it. Ick :) that'd do it yeah."
Javelin looks around for a stack of "Queue Guru" buttons for the participants.
:)
Trispis grins at Jav, I'll leave an edited WHO (no sites) in the log. (:
Sat Feb 14 23:29:58 1998
Vedui says, "Eh Jav, ya always want contributions to the God Manual.. how
about putting in a section of how the queue works? ;)"
Vedui says, "unless ya already did and I just aint read it recently enuf ;)"
Javelin says, "Good idea. You can write one now and send it to me. :)"
Vedui bleahs. Sure... as soon as I finish half of my other work ;)
Trispis says, "I'll have this log ready tomorrow... you can copy/paste the
queue portion over to the manual. (:"
Vedui looks at his calendar, "is next year okay? ;)"
Javelin knows how you feel. :) "Well, I guess we'll finish here. Thanks for
coming."
Vedui applauds
Vedui *8)
Trispis applauds also and walks once again to the front of the room.
Trispis shakes Javelin's hand (sorry for the powerplay) and says, "Class
dismissed. Thanks for attending. The log will be available at
ftp://mush101.pennmush.org/mush101/ClassLogs ... tomorrow afternoon."
Javelin takes Two-step.
Javelin takes Race Condition.
Javelin takes Semaphore Solution.
Javelin takes Partial Fix.
Trispis stops logging.