only occupants are allowed to send morningmessagess to the room

programmer:
=sleep randoml 1 0 1000l
self=$R part 0l
other=$self switch {hacker=#serf serf=#hacker}
All of the players in this game are programmers and we will know which type we are based on the fiber name passed in the right argument ($R), as in many of my previous examples.
crew=#line take
case=((#line + $self) peek 3l) switch
=(((#line + $self) peek 1l) and (#line + $other) peek 2l) switch {=#twoeach =#none}
As programmers arrive at the dock they examine the line to see whether their arrival would form a complete crew to cross the river.
The two relevant cases are when there are already three of the same type (#serf or #hacker) as #allsame, and when there are one of the same type and two
Otherwise the new arrival will have to get in line until a crew can form.
<-$case switch
crew=(#line + $self) dispatch 3l
<-$crew.S part 1 2l
Remember we are still inside of the take block here.
So only one new arrival can be in this section at once.
If the crew is #allsame then the new arrival dispatches those three programmers out of the waiting line.
And yields the names of his fellow crew members (not including himself) out of the take block.
crew0=(#line + $other) dispatch 2l
crew1=(#line + $self) dispatch 1l
<-($crew0.S append $crew1.S) part 1 2l
In the #twoeach case the logic is much the same but we have to call dispatch twice and append the results together to get the full list of crew members, again, not including the new arrival, who will become the captain for the journey.
=(#line + $R) write {i=++}
<-#nothing
In the final case there is no full crew and the programmer writes a message on the blackboard indicating that she is waiting in line.
Note that she does not a because the current fiber is still in the critical section that would prevent the next fiber from inspecting the line.
=(not $crew equals #nothing) switch
=#boat take
=cwrite "captain " + (string $R) + "'s crew is " + " " delimit string $crew
=(#crew + $crew) write {i=++ ++ ++}
If this fiber established a full crew then the names of the crew members will be in the variable $crew otherwise it will contain #nothing.
In this case the current fiber will be the captain.
Note that I am using another mutually-exclusive take block around this section.
That is to ensure that only one crew may occupy the boat at a time.
It is possible that there could be multiple captains and crews that have exited #line and are now waiting to get into the #boat.
So the captain will occupy the #boat take block for the entire period of the journey.
The captain writes #crew messages to the members of $crew to signal them to get in the boat.
You will see how this works in a moment.
=(#boat + $R) write {i=++}
=#boat gawk 4l
Next the captain himself gets in the boat, and waits for the other three crew members using the gawk operator.
gawk was just introduced in my post on the .
It works just like dispatch except without actually consuming the messages.
=sleep randoml 1 0 1000l
=(#land + $crew) write {i=++ ++ ++}
=#boat throttle 2l
Simulate the time taken to paddle across the river.
Then write #land messages to the crew members to let them know its time to get off the boat.
Finally wait for the entire crew to get off the boat.
Using 2l as the right argument of throttle waits until there are less than two members, since the captain is one.
=cwrite "captain " + (string $R) + " is getting off the boat"
=(#boat + $R) dispatch 1l
Finally the captain gets off the boat.
=(#line + $R) throttle 1l
=(#crew + $R) dispatch 1l
=(#boat + $R) write {i=++}
=cwrite (string $R) + " got on the boat"
In the alternative case this fiber is a passenger.
Wait to be taken out of line by the captain.
Then wait for the #crew message which is the passengers signal that the captain has control of the boat.
Finally board the boat by writing a #boat message.
=(#land + $R) dispatch 1l
=(#boat + $R) dispatch 1l
=cwrite (string $R) + " got off the boat"
Wait for the #land message to be sent by the captain.
Then dispatch the #boat message that represents occupancy of the boat above.
This signals to the captain that the passenger is off the boat.
<-programmer $R
Repeat forever.
h0=fiber {<-programmer #hacker,0l}
h1=fiber {<-programmer #hacker,1l}
h2=fiber {<-programmer #hacker,2l}
h3=fiber {<-programmer #hacker,3l}
s0=fiber {<-programmer #serf,0l}
s1=fiber {<-programmer #serf,1l}
s2=fiber {<-programmer #serf,2l}
s3=fiber {<-programmer #serf,3l}
<-wait $h0
This is just the standard initialization seen in many of my examples.
Here is the complete program.
programmer:
=sleep randoml 1 0 1000l
self=$R part 0l
other=$self switch {hacker=#serf serf=#hacker}
crew=#line take
case=((#line + $self) peek 3l) switch
=(((#line + $self) peek 1l) and (#line + $other) peek 2l) switch {=#twoeach =#none}
<-$case switch
crew=(#line + $self) dispatch 3l
<-$crew.S part 1 2l
crew0=(#line + $other) dispatch 2l
crew1=(#line + $self) dispatch 1l
<-($crew0.S append $crew1.S) part 1 2l
=(#line + $R) write {i=++}
<-#nothing
=(not $crew equals #nothing) switch
=#boat take
=cwrite "captain " + (string $R) + "'s crew is " + " " delimit string $crew
=(#crew + $crew) write {i=++ ++ ++}
=(#boat + $R) write {i=++}
=#boat gawk 4l
=sleep randoml 1 0 1000l
=(#land + $crew) write {i=++ ++ ++}
=#boat throttle 2l
=cwrite "captain " + (string $R) + " is getting off the boat"
=(#boat + $R) dispatch 1l
=(#line + $R) throttle 1l
=(#crew + $R) dispatch 1l
=(#boat + $R) write {i=++}
=cwrite (string $R) + " got on the boat"
=(#land + $R) dispatch 1l
=(#boat + $R) dispatch 1l
=cwrite (string $R) + " got off the boat"
<-programmer $R
h0=fiber {<-programmer #hacker,0l}
h1=fiber {<-programmer #hacker,1l}
h2=fiber {<-programmer #hacker,2l}
h3=fiber {<-programmer #hacker,3l}
s0=fiber {<-programmer #serf,0l}
s1=fiber {<-programmer #serf,1l}
s2=fiber {<-programmer #serf,2l}
s3=fiber {<-programmer #serf,3l}
<-wait $h0
Example Output
Welcome to O2, ask brian if you need help
O2>eval fload "../../src/river.o2"
captain #serf,0l's crew is #hacker,3l #hacker,1l #serf,3l
#hacker,3l got on the boat
#hacker,1l got on the boat
#serf,3l got on the boat
#hacker,3l got off the boat
#hacker,1l got off the boat
#serf,3l got off the boat
captain #serf,0l is getting off the boat
captain #hacker,2l's crew is #serf,2l #serf,1l #hacker,0l
#serf,2l got on the boat
#serf,1l got on the boat
#hacker,0l got on the boat
#serf,2l got off the boat
#serf,1l got off the boat
#hacker,0l got off the boat
captain #hacker,2l is getting off the boat
captain #serf,0l's crew is #hacker,3l #hacker,1l #serf,3l
#hacker,3l got on the boat
#hacker,1l got on the boat
#serf,3l got on the boat
#hacker,3l got off the boat
#hacker,1l got off the boat
#serf,3l got off the boat
captain #serf,0l is getting off the boat
captain #hacker,2l's crew is #serf,2l #serf,1l #hacker,0l
#serf,2l got on the boat
#serf,1l got on the boat
#hacker,0l got on the boat
#serf,2l got off the boat
#serf,1l got off the boat
#hacker,0l got off the boat
captain #hacker,2l is getting off the boat
captain #hacker,1l's crew is #serf,0l #serf,3l #hacker,3l
#serf,0l got on the boat
#serf,3l got on the boat
#hacker,3l got on the boat
#serf,0l got off the boat
#serf,3l got off the boat
#hacker,3l got off the boat
captain #hacker,1l is getting off the boat
captain #hacker,2l's crew is #serf,1l #serf,2l #hacker,0l
#serf,1l got on the boat
#serf,2l got on the boat
#hacker,0l got on the boat
#serf,1l got off the boat
#serf,2l got off the boat
#hacker,0l got off the boat
captain #hacker,2l is getting off the boat
captain #hacker,3l's crew is #serf,3l #serf,0l #hacker,1l
#serf,3l got on the boat
#serf,0l got on the boat
#hacker,1l got on the boat
#serf,3l got off the boat
#serf,0l got off the boat
#hacker,1l got off the boat
captain #hacker,3l is getting off the boat
captain #serf,0l's crew is #hacker,0l #hacker,2l #serf,2l
#hacker,0l got on the boat
#hacker,2l got on the boat
#serf,2l got on the boat
#hacker,0l got off the boat
#hacker,2l got off the boat
#serf,2l got off the boat
captain #serf,0l is getting off the boat
captain #hacker,3l's crew is #serf,1l #serf,0l #hacker,1l
#serf,1l got on the boat
#serf,0l got on the boat
#hacker,1l got on the boat
#serf,1l got off the boat
#serf,0l got off the boat
#hacker,1l got off the boat
captain #hacker,3l is getting off the boat
captain #hacker,0l's crew is #serf,3l #serf,2l #hacker,2l
#serf,3l got on the boat
#serf,2l got on the boat
#hacker,2l got on the boat
#serf,3l got off the boat
#serf,2l got off the boat
#hacker,2l got off the boat
captain #hacker,0l is getting off the boat
captain #serf,1l's crew is #hacker,1l #hacker,3l #serf,0l
#hacker,1l got on the boat
#hacker,3l got on the boat
#serf,0l got on the boat
#hacker,1l got off the boat
#hacker,3l got off the boat
#serf,0l got off the boat
captain #serf,1l is getting off the boat
captain #hacker,2l's crew is #serf,2l #serf,3l #hacker,1l
#serf,2l got on the boat
#serf,3l got on the boat
#hacker,1l got on the boat
#serf,2l got off the boat
#serf,3l got off the boat
#hacker,1l got off the boat
captain #hacker,2l is getting off the boat
captain #serf,1l's crew is #hacker,3l #hacker,0l #serf,0l
#hacker,3l got on the boat
#hacker,0l got on the boat
#serf,0l got on the boat
#hacker,3l got off the boat
#hacker,0l got off the boat
#serf,0l got off the boat
captain #serf,1l is getting off the boat
captain #hacker,2l's crew is #serf,3l #serf,2l #hacker,1l
#serf,3l got on the boat
#serf,2l got on the boat
#hacker,1l got on the boat
#serf,3l got off the boat
#serf,2l got off the boat
#hacker,1l got off the boat
captain #hacker,2l is getting off the boat
captain #hacker,0l's crew is #serf,1l #serf,0l #hacker,3l
#serf,1l got on the boat
#serf,0l got on the boat
#hacker,3l got on the boat
#serf,1l got off the boat
#serf,0l got off the boat
#hacker,3l got off the boat
captain #hacker,0l is getting off the boat
captain #hacker,1l's crew is #serf,2l #serf,1l #hacker,2l
#serf,2l got on the boat
#serf,1l got on the boat
#hacker,2l got on the boat
#serf,2l got off the boat
#serf,1l got off the boat
#hacker,2l got off the boat
captain #hacker,1l is getting off the boat
captain #hacker,0l's crew is #serf,3l #serf,0l #hacker,3l
#serf,3l got on the boat
#serf,0l got on the boat
#hacker,3l got on the boat
#serf,3l got off the boat
#serf,0l got off the boat
#hacker,3l got off the boat
captain #hacker,0l is getting off the boat
captain #hacker,3l's crew is #serf,0l #serf,2l #hacker,1l
#serf,0l got on the boat
#serf,2l got on the boat
#hacker,1l got on the boat
#serf,0l got off the boat
#serf,2l got off the boat
#hacker,1l got off the boat
captain #hacker,3l is getting off the boat
captain #hacker,0l's crew is #serf,3l #serf,1l #hacker,2l
#serf,3l got on the boat
#serf,1l got on the boat
#hacker,2l got on the boat
#serf,3l got off the boat
#serf,1l got off the boat
#hacker,2l got off the boat
captain #hacker,0l is getting off the boat
captain #hacker,2l's crew is #serf,0l #serf,2l #hacker,3l
#serf,0l got on the boat
#serf,2l got on the boat
#hacker,3l got on the boat
#serf,0l got off the boat
#serf,2l got off the boat
#hacker,3l got off the boat
captain #hacker,2l is getting off the boat
captain #hacker,0l's crew is #serf,3l #serf,1l #hacker,2l
#serf,3l got on the boat
#serf,1l got on the boat
#hacker,2l got on the boat
#serf,3l got off the boat
#serf,1l got off the boat
#hacker,2l got off the boat
captain #hacker,0l is getting off the boat
captain #serf,1l's crew is #hacker,1l #hacker,2l #serf,0l
#hacker,1l got on the boat
#hacker,2l got on the boat
#serf,0l got on the boat
#hacker,1l got off the boat
#hacker,2l got off the boat
#serf,0l got off the boat
captain #serf,1l is getting off the boat
captain #hacker,0l's crew is #serf,2l #serf,3l #hacker,3l
#serf,2l got on the boat
#serf,3l got on the boat
#hacker,3l got on the boat
#serf,2l got off the boat
#serf,3l got off the boat
#hacker,3l got off the boat
captain #hacker,0l is getting off the boat
captain #serf,2l's crew is #hacker,3l #hacker,1l #serf,1l
#hacker,3l got on the boat
#hacker,1l got on the boat
#serf,1l got on the boat
#hacker,3l got off the boat
#hacker,1l got off the boat
#serf,1l got off the boat
captain #serf,2l is getting off the boat
captain #hacker,0l's crew is #serf,0l #serf,3l #hacker,2l
#serf,0l got on the boat
#serf,3l got on the boat
#hacker,2l got on the boat
#serf,0l got off the boat
#serf,3l got off the boat
#hacker,2l got off the boat
captain #hacker,0l is getting off the boat
captain #serf,2l's crew is #hacker,3l #hacker,1l #serf,1l
#hacker,3l got on the boat
#hacker,1l got on the boat
#serf,1l got on the boat
#hacker,3l got off the boat
#hacker,1l got off the boat
#serf,1l got off the boat
captain #serf,2l is getting off the boat
captain #hacker,2l's crew is #serf,0l #serf,3l #hacker,0l
#serf,0l got on the boat
#serf,3l got on the boat
#hacker,0l got on the boat
#serf,0l got off the boat
#serf,3l got off the boat
#hacker,0l got off the boat
captain #hacker,2l is getting off the boat
captain #hacker,0l's crew is #hacker,3l #hacker,2l #hacker,1l
#hacker,3l got on the boat
#hacker,2l got on the boat
#hacker,1l got on the boat
#hacker,3l got off the boat
#hacker,2l got off the boat
#hacker,1l got off the boat
captain #hacker,0l is getting off the boat
captain #serf,0l's crew is #serf,3l #serf,1l #serf,2l
#serf,3l got on the boat
#serf,1l got on the boat
#serf,2l got on the boat
#serf,3l got off the boat
#serf,1l got off the boat
#serf,2l got off the boat
I included a little more output than usual in order to prove that this program will form those with all hackers or serfs, or two of each.
Discussion
At this stage all I can really say is that I'm getting tired of working on concurrency problems.
Which is how I should feel at this point.
This is number eleven out my set of twelve.
One of the best techniques I learned in jazz school was to practice at one idea, in as many variations as I could come up with, until it was completely beaten into the ground.
This happens way after the idea stops being fun and new and interesting.
You have to keep going until you are totally sick of it.
I had way more patience for this style of practice than most people.
And it works.
I'm finding that it works for programming as well, especially in the process of developing a language.
Anyway it feels like O2 is getting pretty good at expressing concurrency problems.
I'm going to bang out one more of these puppies and then were going to try something different.
Today&#8217;s problem tested my wits, my patience, and of course O2, my new programming language.
I started with The Unisex Bathroom Problem as described in .
He describes the problem as follows:
I wrote this problem when a friend of mine left her position teaching physics at Colby College and took a job at Xerox. She was working in a cubicle in the basement of a concrete monolith, and the nearest women’s bathroom was two floors up. She proposed to the Uberboss that they convert the men’s bathroom on her floor to a unisex bathroom, sort of like on Ally McBeal. The Uberboss agreed, provided that the following synchronization constraints can be maintained:
There cannot be men and women in the bathroom at the same time.
There should never be more than three employees squandering company time in the bathroom.
Of course the solution should avoid deadlock. For now, though, don’t worry about starvation. You may assume that the bathroom is equipped with all the semaphores you need.
Downey then provides two concise solutions to the problem using semaphores.
The first one is highly concurrent but prone to starvation.
It involves a LightSwitch; a higher level abstraction of a semaphore, on the outside of a Multiplex.
The lightswitch controls whether men or women are allowed in the room at a given time.
And the multiplex ensures that only three occupants are in the room concurrently.
The problem is that while one sex is occupying the room, if the other sex is waiting outside they may be skipped over and over again by new arrivals of the same sex that is in the room.
The second one is starvation free but suffers from reduced concurrency.
Basically everyone goes in first-in-first-out order.
There will only be multiple occupants in the bathroom if multiple men or women entered the line together.
In the degenerate case, men and women alternate perfectly, and only one person can use the bathroom at a time.
I could have implemented either of these solutions in O2.
But I felt that since I am introducing a new language that aims to be good at solving concurrency problems I should have a solution that is highly concurrent and free of starvation.
So I added the following constraints to my version of the problem.
I call it the Collegial Facility.
If the room is occupied by men/women and a woman/man arrives at the door, she/he should step aside and let any man/woman that arrives go first, in order to maximize the throughput of the bathroom.
If there are one or more women/men waiting in this &#8220;skip line&#8221;, then they should only be skipped by at most three new arrivals.
Once they have been skipped the third time, all of the people that have been skipped get to go before any new arrival can access the bathroom.
My solution requires a separate &#8220;bathroom controller&#8221; fiber to coordinate entries and exits from the bathroom.
In general I like to avoid using these kinds of helper threads, but sometimes they are necessary.
In this case the bathroom fiber can suspend at the necessary times in a way that would not work for one of the person fibers if they were inside a mutually-exclusive take block.
Also, many real systems like guis, transaction processing systems, etc&#8230; involve serial event processor loops so it is valuable to show how those can be implemented in O2.
mysex=$R part 0l
We shall start with the definition of the person fiber.
The right argument is a symbol (tuple) consisting of t #man or #woman and an integer unique to that fiber.
=sleep randoml 1 0 1000l
Randomize the attempts enter the bathroom.
=(#door,entry + $me) write {i=++}
=(#door,entry + $me) throttle 1l
=(#skip + $me) throttle 1l
This is a new pattern you haven&#8217;t seen before.
The throttle operator can be used to implement a kind of request response between fibers.
The person writes a message under the symbol #door,entry and then uses throttle to wait until another fiber dispatches that same message from the blackboard.
The room fiber will decide whether this person should enter the skip line.
All that is necessary to make the person respect the skip line is to introduce the second throttle using the symbol #skip with $me appended.
=(#room + $me) write {i=++}
=(#ack + $me) write {i=++}
=cwrite (string $me) + " entered the bathroom"
Once allowed through the entry and possibly removed from the skip line, the person enters the bathroom.
After entering the room the person writes back on the symbol #ack.
I will show you when I get to the room code why this is important.
Once letting a person in, the room has to wait for the person to actually enter in order to avoid potential race conditions.
=sleep randoml 1 0 1000l
=cwrite (string $me) + " left the bathroom"
=(#room + $me) dispatch 1l
=(#door,exit + $me) write {i=++}
Person uses the bathroom for a random period of time, then exits by dispatching the line previously written.
In addition to removing themselves from the room, the person writes an additional message explicitly indicating that they exited the room.
<-person $R
Repeat from the top.
Now for the room code:
=#room throttle 3l
Each lap for the room fiber begins by waiting until the the room is not full.
throttle handles this.
Recall that the person fiber writes a message to the #room symbol in order to indicate that the person is in the room, and dispatches that same symbol upon leaving.
next=#door gawk 1l
The gawk operator is yet another variation of dispatch, along with throttle and peek.
gawk lets you actually look at the messages that dispatch would yield if you invoked it with the same arguments.
The only difference is that gawk does not remove the message from the queue.
In this way the room fiber can look at like a kind of lightweight server, inspecting messages and then deciding how to act upon them.
Once done it will dispatch the message, indicating to the person fiber that it is ok to continue.
2l) switch
In prior posts I have used the if operator to do conditional branches.
I hate conditional logic.
I prefer code that proceeds in a straight line, such as the person fiber above.
But I can not always have my way.
So I introduced switch which is a less ugly version of conditional branching.
On the left argument it takes a single boolean or symbol value.
In the case of a boolean it will execute the first or second branch on the right depending on whether the value is true or false.
In the case of a symbol it chooses the branch to execute using its name in the block on the right.
So in this case if the event message symbol is #entry then it chooses the branch otherwise it chooses the #exit branch as you shall see.
In the entry block there is a nested conditional which checks to see if the right argument ($R) is greater than 2l.
This is how the room controls the case where people have been skipped too many times.
={=#room throttle 1l =drain {} <-room 0l}
Wait until the room is empty.
Then invoke the drain operator which will follow below.
The drain operator lets everyone in the skip line use the restroom before continuing.
Then reenter the room operator with the right argument, the skip count set to zero.
othersex=($next.S part 2l) switch {man=#woman woman=#man}
sexok=not (#room + $othersex) peek 1l
=cwrite (string $next.S) + " at the entry " + ($sexok switch {="(ok)" ="(not ok)"})
Now begin the case where a person is at the entry and the people in the skip line have not been skipped too many times.
Here the switch operator is used again to determine the symbol for the other sex.
Then we calculate the $sexok flag which is false if there are members of the other sex in the room, according to the peek operator.
skip=$sexok switch
=(#skip peek 1l) switch {=$R + 1l =0l}
={=(#skip + $next.S part 2 3l) write {i=++} <-$R}
Another use of switch, you can see why I had to do something about the aesthetics of if before posting this example.
The new skip count will be stored in the variable $skip.
If $sexok is true, then check to see if someone is in the skip line and increment the skip count before returning.
Otherwise we put the person into the skip line by writing a new message to the symbol #skip appended with the name of the fiber that is at the entry.
In this case the skip count remains the same.
=$next.S dispatch 1l
=($sexok) switch {=#ack dispatch 1l}
<-room $skip
After deciding whether the person is to enter the room or go into the skip line, we dispatch the symbol of the next message that was obtained from the gawk operator.
This will cause the person fiber to advance to the next stage which will either be the skip line or they will actually enter the bathroom (finally!).
If they entered the room then the room fiber should wait for the #ack which will only happen after the person
that is written to the #room symbol.
Another way to accomplish the same thing would be to read from the line given by result of $next.S dispatch 1l.
exit=((not #room peek 1l) and #skip peek 1l) switch
={=$next.S dispatch 1l =drain {} <-room 0l}
={=$next.S dispatch 1l <-room $R}
This is the block of code that will evaluate if the room receives a #door,exit message.
If the room is now empty and there are people in the skip line then all of the people in the skip line should get to go next.
Otherwise just take it from the top.
<-(#skip peek 1l) switch
=#skip dispatch 1l
=#ack dispatch 1l
=#room throttle 3l
<-drain {}
This is the drain routine as promised.
It is recursive.
It removes a person from the skip line, waiting for the #ack as they enter the room.
Then it waits as long is it takes until there a seat free in the room and lets the next person in, until there is no one left in the room.
b=fiber {<-#none room 0l}
m0=fiber {<-person #man,0l}
m1=fiber {<-person #man,1l}
m2=fiber {<-person #man,2l}
m3=fiber {<-person #man,3l}
m4=fiber {<-person #man,4l}
m5=fiber {<-person #man,5l}
m6=fiber {<-person #man,6l}
m7=fiber {<-person #man,7l}
w8=fiber {<-person #man,8l}
w0=fiber {<-person #woman,0l}
w1=fiber {<-person #woman,1l}
w2=fiber {<-person #woman,2l}
w3=fiber {<-person #woman,3l}
w4=fiber {<-person #woman,4l}
w5=fiber {<-person #woman,5l}
w6=fiber {<-person #woman,6l}
w7=fiber {<-person #woman,7l}
w8=fiber {<-person #woman,8l}
<-test0 {}
I configured this test with eight man and eight woman threads.
I used a few extra configurations to test this program but I will omit them here in the name of brevity (For some definition of brevity anyway
Here is the full text of the program.
It is the most complex O2 example I have published yet.
mysex=$R part 0l
othersex=$mysex switch {man=#woman woman=#man}
=sleep randoml 1 0 1000l
=(#door,entry + $me) write {i=++}
=(#door,entry + $me) throttle 1l
=(#skip + $me) throttle 1l
=(#room + $me) write {i=++}
=(#ack + $me) write {i=++}
=cwrite (string $me) + " entered the bathroom"
=sleep randoml 1 0 1000l
=cwrite (string $me) + " left the bathroom"
=(#room + $me) dispatch 1l
=(#door,exit + $me) write {i=++}
<-person $R
=#room throttle 3l
next=#door gawk 1l
2l) switch
={=#room throttle 1l =drain {} <-room 0l}
othersex=($next.S part 2l) switch {man=#woman woman=#man}
sexok=not (#room + $othersex) peek 1l
=cwrite (string $next.S) + " at the entry " + ($sexok switch {="(ok)" ="(not ok)"})
skip=$sexok switch
=(#skip peek 1l) switch {=$R + 1l =0l}
={=(#skip + $next.S part 2 3l) write {i=++} <-$R}
=$next.S dispatch 1l
=($sexok) switch {=#ack dispatch 1l}
<-room $skip
exit=((not #room peek 1l) and #skip peek 1l) switch
={=$next.S dispatch 1l =drain {} <-room 0l}
={=$next.S dispatch 1l <-room $R}
<-(#skip peek 1l) switch
=#skip dispatch 1l
=#ack dispatch 1l
=#room throttle 3l
<-drain {}
b=fiber {<-#none room 0l}
m0=fiber {<-person #man,0l}
m1=fiber {<-person #man,1l}
m2=fiber {<-person #man,2l}
m3=fiber {<-person #man,3l}
m4=fiber {<-person #man,4l}
m5=fiber {<-person #man,5l}
m6=fiber {<-person #man,6l}
m7=fiber {<-person #man,7l}
w8=fiber {<-person #man,8l}
w0=fiber {<-person #woman,0l}
w1=fiber {<-person #woman,1l}
w2=fiber {<-person #woman,2l}
w3=fiber {<-person #woman,3l}
w4=fiber {<-person #woman,4l}
w5=fiber {<-person #woman,5l}
w6=fiber {<-person #woman,6l}
w7=fiber {<-person #woman,7l}
w8=fiber {<-person #woman,8l}
<-test0 {}
The Output
Welcome to O2, ask brian if you need help
O2>eval fload "../../src/facility.o2"
#door,entry,man,4l at the entry (ok)
#man,4l entered the bathroom
#door,entry,man,7l at the entry (ok)
#man,7l entered the bathroom
#door,entry,woman,1l at the entry (not ok)
#door,entry,man,2l at the entry (ok)
#man,2l entered the bathroom
#man,7l left the bathroom
#door,entry,woman,0l at the entry (not ok)
#door,entry,man,8l at the entry (ok)
#man,8l entered the bathroom
#man,2l left the bathroom
#door,entry,man,5l at the entry (ok)
#man,5l entered the bathroom
#man,4l left the bathroom
#man,8l left the bathroom
#man,5l left the bathroom
#woman,1l entered the bathroom
#woman,0l entered the bathroom
#door,entry,man,3l at the entry (not ok)
#door,entry,man,6l at the entry (not ok)
#door,entry,woman,3l at the entry (ok)
#woman,3l entered the bathroom
#woman,0l left the bathroom
#door,entry,woman,7l at the entry (ok)
#woman,7l entered the bathroom
#woman,7l left the bathroom
#door,entry,woman,8l at the entry (ok)
#woman,8l entered the bathroom
#woman,3l left the bathroom
#woman,8l left the bathroom
#woman,1l left the bathroom
#man,3l entered the bathroom
#man,6l entered the bathroom
#door,entry,man,4l at the entry (ok)
#man,4l entered the bathroom
#man,6l left the bathroom
#door,entry,woman,4l at the entry (not ok)
#door,entry,woman,2l at the entry (not ok)
#door,entry,man,0l at the entry (ok)
#man,0l entered the bathroom
#man,3l left the bathroom
#door,entry,woman,6l at the entry (not ok)
#door,entry,woman,5l at the entry (not ok)
#door,entry,man,1l at the entry (ok)
#man,1l entered the bathroom
#man,1l left the bathroom
#door,entry,man,2l at the entry (ok)
#man,2l entered the bathroom
#man,4l left the bathroom
#man,0l left the bathroom
#man,2l left the bathroom
#woman,4l entered the bathroom
#woman,2l entered the bathroom
#woman,6l entered the bathroom
#woman,2l left the bathroom
#woman,5l entered the bathroom
#woman,6l left the bathroom
#door,entry,man,7l at the entry (not ok)
#door,entry,man,8l at the entry (not ok)
#door,entry,woman,7l at the entry (ok)
#woman,7l entered the bathroom
#woman,4l left the bathroom
#door,entry,woman,0l at the entry (ok)
#woman,0l entered the bathroom
#woman,5l left the bathroom
#door,entry,man,5l at the entry (not ok)
#door,entry,woman,3l at the entry (ok)
#woman,3l entered the bathroom
#woman,7l left the bathroom
#woman,3l left the bathroom
#woman,0l left the bathroom
#man,7l entered the bathroom
#man,8l entered the bathroom
#man,5l entered the bathroom
#man,5l left the bathroom
#door,entry,woman,1l at the entry (not ok)
#door,entry,man,6l at the entry (ok)
#man,6l entered the bathroom
#man,8l left the bathroom
#door,entry,woman,8l at the entry (not ok)
#door,entry,man,4l at the entry (ok)
#man,4l entered the bathroom
I won't break this down line by line but if you do you can see that the bathroom remains highly concurrent while avoiding starvation and obeying the constraints set out in the original problem.
Discussion
When I first added the throttle and peek operators into O2 I thought that they would not be used much in practice.
But now that I have them I find myself using them all over.
I don't believe I could have solved this problem at all without them.
Also, I think that a number of my earlier posts could have been written more elegantly with the benefit of these operators.
In this post I introduced yet another operato gawk.
gawk lets you actually look at the data that would be dispatched without actually experiencing the side effect of dispatch.
I think that this operator is going to come in handy in my upcoming series on distributed computing in O2.
But who knows?
I don't really know what pieces I need until I start trying to build stuff with them.
The new switch operator is another example.
I think I am going to be able to get rid of ugly old if entirely.
It is pretty exciting to feel the language getting better and stronger through repeated use and practice, which is the whole purpose of this blog.
I also need to explain the expression to the right of the write operator: {i=++ ++ fiber=$R append $R}.
If you want to write to two symbols in one shot then you need to pass a block where all the elements in the block are vectors with two elements.
The first element in each vector corresponds to the first row/symbol and so on.
But what on earth is &#8220;++ ++&#8221;?
This is a little bit of magic that I invented to get around a problem I have been having repeatedly while working these concurrency problems.
When I created signals and the O2 blackboard I designed it to avoid storing duplicate data, meaning that if you write to the blackboard and you write the same values that were already there before (for a particular symbol) it becomes a no-op.
This makes it possible to handle huge numbers of symbols and columns in the blackboard.
There are other reasons as well which I will discuss on my future dedicated post about the blackboard.
But it has become a problem in trying to use the blackboard for concurrency and messaging between fibers.
In this case nothing will change between laps so writing to the blackboard will be a noop which would cause the whole program to reach a deadlock state.
To solve this problem I created a new datatype that I am calling an IncrOp.
It is just another kind of vector like long, string, or double, but it has a special behavior in conjunction with the write operator, where it will increment whatever value was there prior, for that symbol.
You can use this whenever you need to ensure that you don&#8217;t write duplicate data to the blackboard by accident.
=(#bound + $h.fiber) dispatch 1l
Now wait for both fibers to write back.
The left hand argument to dispatch is a vector of both symbols.
The right hand argument tells dispatch to wait for one response on each symbol.
Waiting on both fibers here ensures that we do not release the take block until both hydrogens acknowledge the binding relationship.
=cwrite (string $R) + " done"
<-oxygen $R
Exit the take block, letting the next oxygen go, and repeat.
=(#wait + $R) write eval {i=++ fiber=$R}
Now we move on to the hydrogen fiber.
This line writes to the blackboard signaling that this hydrogen fiber is waiting to bond.
o=(#init + $R) dispatch 1l
Wait for a response from the oxygen fiber.
=cwrite (string $R) + " getting bound to " + string $o.fiber
=(#bound + $R) write eval {i=++ fiber=$R}
Once we get a signal from the oxygen fiber, write back.
<-hydrogen $R
Rinse, wash and repeat.
h0=fiber {<-hydrogen #h,0l}
h1=fiber {<-hydrogen #h,1l}
h2=fiber {<-hydrogen #h,2l}
h3=fiber {<-hydrogen #h,3l}
h4=fiber {<-hydrogen #h,4l}
o0=fiber {<-oxygen #o,0l}
o1=fiber {<-oxygen #o,1l}
o2=fiber {<-oxygen #o,2l}
o3=fiber {<-oxygen #o,3l}
<-wait $h0
Setup a bunch of hydrogen and oxygen threads and let'em rip.
Here is the entire program without commentary.
Even though the explanations can be very verbose, the program itself is very concise.
h=#wait dispatch 2l
=#bond take
=cwrite (string $R) + " initiating bonds with " + " " delimit string $h.fiber
=(#init + $h.fiber) write eval {i=++ ++ fiber=$R append $R}
=(#bound + $h.fiber) dispatch 1l
=cwrite (string $R) + " done"
<-oxygen $R
=(#wait + $R) write eval {i=++ fiber=$R}
o=(#init + $R) dispatch 1l
=cwrite (string $R) + " getting bound to " + string $o.fiber
=(#bound + $R) write eval {i=++ fiber=$R}
<-hydrogen $R
h0=fiber {<-hydrogen #h,0l}
h1=fiber {<-hydrogen #h,1l}
h2=fiber {<-hydrogen #h,2l}
h3=fiber {<-hydrogen #h,3l}
h4=fiber {<-hydrogen #h,4l}
o0=fiber {<-oxygen #o,0l}
o1=fiber {<-oxygen #o,1l}
o2=fiber {<-oxygen #o,2l}
o3=fiber {<-oxygen #o,3l}
<-wait $h0
Output of the Building H2O Solution
When you run this program you will get output that looks like this:
Welcome to O2, ask brian if you need help
O2>eval fload "../../src/water.o2"
#o,0l initiating bonds with #h,1l #h,0l
#h,1l getting bound to #o,0l
#h,0l getting bound to #o,0l
#o,0l done
#o,1l initiating bonds with #h,2l #h,3l
#h,2l getting bound to #o,1l
#h,3l getting bound to #o,1l
#o,1l done
#o,3l initiating bonds with #h,4l #h,1l
#h,4l getting bound to #o,3l
#h,1l getting bound to #o,3l
#o,3l done
#o,0l initiating bonds with #h,0l #h,2l
#h,0l getting bound to #o,0l
#h,2l getting bound to #o,0l
#o,0l done
#o,2l initiating bonds with #h,3l #h,4l
#h,3l getting bound to #o,2l
#h,4l getting bound to #o,2l
#o,2l done
#o,3l initiating bonds with #h,1l #h,0l
#h,1l getting bound to #o,3l
#h,0l getting bound to #o,3l
#o,3l done
#o,0l initiating bonds with #h,2l #h,3l
#h,2l getting bound to #o,0l
#h,3l getting bound to #o,0l
#o,0l done
#o,2l initiating bonds with #h,4l #h,1l
#h,4l getting bound to #o,2l
#h,1l getting bound to #o,2l
#o,2l done
#o,1l initiating bonds with #h,0l #h,2l
#h,0l getting bound to #o,1l
#h,2l getting bound to #o,1l
#o,1l done
#o,3l initiating bonds with #h,3l #h,4l
#h,3l getting bound to #o,3l
#h,4l getting bound to #o,3l
#o,3l done
#o,0l initiating bonds with #h,1l #h,0l
#h,1l getting bound to #o,0l
#h,0l getting bound to #o,0l
#o,0l done
#o,2l initiating bonds with #h,2l #h,3l
#h,2l getting bound to #o,2l
#h,3l getting bound to #o,2l
#o,2l done
#o,1l initiating bonds with #h,4l #h,1l
#h,4l getting bound to #o,1l
#h,1l getting bound to #o,1l
#o,1l done
#o,3l initiating bonds with #h,0l #h,3l
#h,0l getting bound to #o,3l
#h,3l getting bound to #o,3l
#o,3l done
#o,0l initiating bonds with #h,2l #h,4l
#h,2l getting bound to #o,0l
#h,4l getting bound to #o,0l
#o,0l done
#o,1l initiating bonds with #h,1l #h,0l
#h,1l getting bound to #o,1l
#h,0l getting bound to #o,1l
#o,1l done
#o,3l initiating bonds with #h,3l #h,2l
#h,3l getting bound to #o,3l
#h,2l getting bound to #o,3l
#o,3l done
#o,0l initiating bonds with #h,4l #h,0l
#h,4l getting bound to #o,0l
#h,0l getting bound to #o,0l
#o,0l done
#o,2l initiating bonds with #h,1l #h,2l
#h,1l getting bound to #o,2l
#h,2l getting bound to #o,2l
#o,2l done
The program is forming the water molecules as expected.
You can see that the three required fibers are passing through the barrier together and that they are accurately recording which other fibers they are interacting with.
Conclusion - O2 Fibers Can Do Request/Response
In this program we got to see how O2's concurrency operators write, dispatch and take can be used to implement complex transactional messaging between fibers.
This solution rests on the ability to have either fiber waiting on the other one using the dispatch operator, and also the dispatch operator's unique ability to wait on messages from multiple fibers.
This is yet another example of how array programming concepts can be usefully applied to concurrency problems.
This solution also shows how write and dispatch can be used together to implement a request-response style of communication between fibers.
Here I used symbols to create a crude protocol for correlating the requests and responses.
I might come up with a simpler way to do this in the future.
This is post seven in my twelve part series on concurrency problems in O2.
In a database application this could mean that all the readers are getting data, but the data they are getting is stale because the writer could not update the database.
So let&#8217;s assume you have an application where you want to serve incoming readers as quickly as possible.
But you want any changes (from the writer) to be seen by readers as quickly as possible.
The first thing you want to do is make sure readers should not wait for each other.
We did that in Part I.
The second thing you want to do is ensure that when the writer arrives, any waiting readers can finish with their work, but new readers will wait until the writer is done.
In traditional solutions this is accomplished using shared counter variables and several semaphores to manage concurrency.
The O2 solution will have the same effect but is, in my opinion, easier to understand and implement correctly.
We will use the blackboard as a communication channel for the writer to tell the readers that they need to wait.
Good Morning Boulder
Solution to the Readers-Writers Problem
=#wait write {hold=true}
We begin by defining an operator for the writer.
The first thing the writer does is write to the blackboard under the symbol #wait.
There is nothing magical about the symbol #wait, but it has to be agreed upon by the reader and the writer.
The message written has a variable &#8220;hold&#8221; with the boolean value true.
This is going to signal to the reader that the writer is present and that it should wait.
=cwrite "writer begins writing"
=sleep randoml 1 0 1000l
=cwrite "writer done writing"
=#wait write {hold=false}
In this case the right argument $R receives a vector containing multiple symbols, one for each reader.
This vector becomes the left argument to the take operator, which suspends evaluation until the writer fiber can gain exclusive access to all of the symbols in $R.
This means that it will wait for any readers that are already in progress.
When the writer is done, it writes the value false to the hold variable under the symbol #wait.
This signals waiting readers that they may now proceed, since the writer is done.
=sleep randoml 1 0 1000l
<-writer $R
Let the writer sleep for a while and then continue by reentering.
This is the end of the writer operator.
A quick note about nomenclature.
Operators are equivalent to functions or subroutines in other languages.
I call them operators because they are allowed to receive two arguments.
One on the right, called $R, and one on the left, called $L.
$L is always optional but the syntax requires that you always pass something into $R, even if it is not referenced.
Traditionally in functional programming, functions can only receive a single argument, but that argument is sometimes a list or a dictionary containing multiple values.
In O2 we have monadic operators that take one argument on the right ($R) and dyadic operators that take arguments on both the right and the left ($R and $L respectively).
signal=#wait last 0l
test:$signal.hold
then:#wait last lines $signal
The reader begins every iteration by reading the most recent state of the #wait symbol in the blackboard.
It does this by using the last operator which takes one or more symbols on the left, and on the right, it takes the line number in the blackboard where you want to start reading.
By passing 0l (zero) here, the reader ensures that last will always return immediately with the most recent state.
If it received a right argument greater than 0l, last would block until the blackboard had an appropriate value at or beyond the requested line number.
The value returned from last will be a signal, which is a tabular data structure that can have multiple rows and columns.
In this case there wil hold, and one row for the symbol #wait.
Then we use the if operator to test the valu using the dot notation to reference columns in the signal value ($signal.hold).
If hold is set to true, reader will call last again, but this time the goal is to block until the value of #wait changes.
The lines operator is used to figure out how many lines were in the blackboard at the point when $signal was created.
This ensures that the reader will not miss any updates to #wait even though there is no concurrency control between the two calls to last.
It's just a couple lines of code but a lot of explanation is required.
That is why I broke this into two posts.
The net result of all of this is that the reader will now check to see if the writer is trying to write.
If the writer is trying to write, the reader will wait until the writer sets hold=false again.
=cwrite "reader " + (string $R) + " begins reading"
=sleep randoml 1 0 1000l
=cwrite "reader " + (string $R) + " done reading"
<-reader $R
At this point the reader is ensured that the writer is either not waiting, or if it is, has not been waiting for long because hold was set to false just moments ago when the writer checked on it.
So the reader will go again and use take to enter its critical section, acquiring the lock that corresponds to just this reader fiber.
This code is identical to the reader code from the prior post with one exception.
In last week's example the reader would sleep for a while after the take block.
This was to allow the writer thread a chance to occasionally get all the locks.
With the improved concurrency control to avoid starving the writer thread, this is now unnecessary.
So I have removed the sleep call to simulate a very aggressive reader.
s:#readers,0l #readers,1l #readers,2l #readers,3l #readers,4l
=#wait write {hold=false}
$s is a vector of symbols that correspond to each reader fiber.
Note that symbols are tuples (ordered lists of typed scalar values).
The elements of each tuple are separated by commas (,).
This allows the blackboard to represent hierarchical data structures and also gives you a neat way to keep many symbols and groups of symbols organized.
w=fiber {<-writer $s}
r={<-fiber {<-reader $R}} each $s
Now launch a single writer and multiple reader fibers.
Wait indefinitely for the writer to finish.
Here is the entire piece without commentary.
=#wait write {hold=true}
=cwrite "writer begins writing"
=sleep randoml 1 0 1000l
=cwrite "writer done writing"
=#wait write {hold=false}
=sleep randoml 1 0 10000l
<-writer $R
signal=#wait last 0l
test:$signal.hold
then:#wait last lines $signal
=cwrite "reader " + (string $R) + " begins reading"
=sleep randoml 1 0 1000l
=cwrite "reader " + (string $R) + " done reading"
<-reader $R
s:#readers,0l #readers,1l #readers,2l #readers,3l #readers,4l
=#wait write {hold=false}
w=fiber {<-writer $s}
r={<-fiber {<-reader $R}} each $s
Example Output of the Readers-Writers Solution
Now let's run this program and see how it compares to the old version without the extra layer of communication to avoid starving the writer thread.
Welcome to O2, ask brian if you need help
O2>eval fload "../../src/rwnostarve.o2"
writer begins writing
{:2l :3l :4l :5l :6l}
O2>writer done writing
reader #readers,0l begins reading
reader #readers,1l begins reading
reader #readers,2l begins reading
reader #readers,3l begins reading
reader #readers,4l begins reading
reader #readers,0l done reading
reader #readers,1l done reading
reader #readers,2l done reading
reader #readers,3l done reading
reader #readers,4l done reading
writer begins writing
writer done writing
reader #readers,0l begins reading
reader #readers,1l begins reading
reader #readers,2l begins reading
reader #readers,3l begins reading
reader #readers,4l begins reading
reader #readers,0l done reading
reader #readers,1l done reading
reader #readers,2l done reading
reader #readers,3l done reading
reader #readers,4l done reading
writer begins writing
writer done writing
reader #readers,0l begins reading
reader #readers,1l begins reading
reader #readers,2l begins reading
reader #readers,3l begins reading
reader #readers,4l begins reading
reader #readers,0l done reading
reader #readers,1l done reading
reader #readers,2l done reading
reader #readers,3l done reading
reader #readers,4l done reading
writer begins writing
writer done writing
reader #readers,0l begins reading
reader #readers,1l begins reading
reader #readers,2l begins reading
reader #readers,3l begins reading
reader #readers,4l begins reading
reader #readers,0l done reading
reader #readers,1l done reading
reader #readers,2l done reading
reader #readers,3l done reading
reader #readers,4l done reading
writer begins writing
writer done writing
reader #readers,0l begins reading
reader #readers,1l begins reading
reader #readers,2l begins reading
reader #readers,3l begins reading
reader #readers,4l begins reading
reader #readers,0l done reading
reader #readers,1l done reading
reader #readers,2l done reading
reader #readers,3l done reading
reader #readers,4l done reading
writer begins writing
writer done writing
reader #readers,0l begins reading
reader #readers,1l begins reading
reader #readers,2l begins reading
reader #readers,3l begins reading
reader #readers,4l begins reading
reader #readers,0l done reading
reader #readers,1l done reading
reader #readers,2l done reading
reader #readers,3l done reading
reader #readers,4l done reading
writer begins writing
writer done writing
reader #readers,0l begins reading
reader #readers,1l begins reading
reader #readers,2l begins reading
reader #readers,3l begins reading
reader #readers,4l begins reading
reader #readers,0l done reading
reader #readers,1l done reading
reader #readers,2l done reading
reader #readers,0l begins reading
reader #readers,1l begins reading
reader #readers,2l begins reading
reader #readers,3l done reading
reader #readers,4l done reading
reader #readers,0l done reading
reader #readers,1l done reading
reader #readers,2l done reading
writer begins writing
writer done writing
reader #readers,3l begins reading
reader #readers,4l begins reading
reader #readers,0l begins reading
reader #readers,1l begins reading
reader #readers,2l begins reading
reader #readers,3l done reading
reader #readers,4l done reading
reader #readers,0l done reading
reader #readers,1l done reading
reader #readers,2l done reading
reader #readers,3l begins reading
reader #readers,4l begins reading
reader #readers,0l begins reading
reader #readers,1l begins reading
reader #readers,2l begins reading
reader #readers,3l done reading
reader #readers,4l done reading
reader #readers,0l done reading
reader #readers,1l done reading
reader #readers,2l done reading
reader #readers,3l begins reading
reader #readers,4l begins reading
reader #readers,0l begins reading
reader #readers,1l begins reading
reader #readers,2l begins reading
reader #readers,3l done reading
reader #readers,4l done reading
reader #readers,0l done reading
reader #readers,1l done reading
reader #readers,2l done reading
reader #readers,3l begins reading
reader #readers,4l begins reading
reader #readers,0l begins reading
reader #readers,1l begins reading
reader #readers,2l begins reading
reader #readers,3l done reading
reader #readers,4l done reading
reader #readers,0l done reading
reader #readers,1l done reading
reader #readers,2l done reading
writer begins writing
writer done writing
Discussion
So does it work or what?
The reader fibers are able to read concurrently (at the same time).
The writer fiber never begins writing until all readers are done reading.
The writer fiber never waits very long to get all of the locks even though the readers are very aggressive.
Why are the readers synchronized with each other?
You might also notice that the readers seem to be synchronized with each other.
In most cases all five readers will finish before the first one begins again.
After doing some research I found that this is due to a bug in my randoml operator, which is based on the .net Random class.
You can pass your own seed into the left argument of randoml, but for simplicity's sake I don't do that in these examples.
What happens is that each fiber creates its own instance of the Random class using the default constructor.
The default constructor uses a seed that is based on the current time.
But because the clock has a limited resolution the Random instances created by each fiber can end up having the same seed, and the producing the same values.
This causes the reader fibers to sleep for the same amount of time and wake up at the same time.
The recommended fix for this in the .net documentation is to share an instance of the Random class.
I might do that but at the moment I don't have a good strategy for sharing instances of values across operators.
Operators are always stateless unless they interact with common infrastructure like the blackboard.
So I need to meditate a bit on how to proceed.
It's kind of a tangent to this post, but a question that could come up.
What about the Third Readers-Writers Problem?
In the CS literature there is also a discussion of a Third Readers-Writers problem.
The first one is the naive version that I did in my prior post.
The second one is the problem of giving preference to writers, which we have just discussed.
But what happens if the writer is too greedy and prevents readers from reading?
This could be just as bad as seeing stale data in your database.
Instead of stale data, you get no data at all because the writer keeps updating the database and never gives you a chance to read!
If I were using classical concurrency control primitives like semaphores I would have to do a third post to solve this problem, and the solution could get very hairy.
Fortunately O2's take operator always enforces first-in-first-out semantics.
This means that if a symbol has been released that would allow two fibers to proceed, the one that has been waiting the longest will get to go first.
This ensures that when the writer releases its symbols, any waiting readers will get to go before the writer goes again.
Where would I use a solution like this?
I would like to point out that you don't ever need to use O2's concurrency control facilities like take and dispatch to safely read and write from the blackboard.
Those operations will always be thread-safe to the extreme.
The purpose of fiber-level concurrency control is to give you control over how your fibers interact with or avoid interfering with each other.
For example, you could have a need to update a database, filesystem, or other external hardware while other fibers are using it.
Fibers are not heavy like threads.
Potentially they can be used to keep tabs and coordinate things out in the real world, like robots in a factory, soldiers on a battlefield, orders on a trading floor, etc...
Object Oriented Programming encouraged us to think about the world as a collection of objects sending messages to each other.
I would rather think of the world as a collection of processes that communicate, coordinate, and compete in order to reach their goals.
That is why I am spending so much time on concurrency in O2.
It has to work and has to be done right.
This is post number six which means I am halfway done.

我要回帖

更多关于 messages三星 的文章

 

随机推荐