►
From YouTube: 2019-11-15 Go study group
Description
Go study group reviews the classic Dining Philosopher problem, but this time with semaphores
A
A
Cool
so
I'm
gonna
comment
comment
out
the
the
solution,
just
to
show
you
how
everything
works.
So
the
problem
that
happened
last
week
is
that
when
I
was
setting
up
the
test,
we
didn't
have
all
the
philosophers
sharing
a
fork,
so
I'm
just
gonna
briefly
go
over
what
the
dining
philosophers
is
one
more
time.
So
we
have
five
philosophers
sitting
around
a
table
and
between
each
of
them
is
one
fork.
A
These
weird
philosophers
like
to
share
Forks
for
some
reason
they
don't
want
to
have
their
own
Forks
and
they
have
to
have
two
forks
to
eat.
So
you
have
five
people,
five
Forks!
You
don't
have
enough
for
everyone
eat
simultaneously.
You
need
to
have
ten
Forks,
so
we
only
have
five.
So
at
most
we
can
have
two
philosophers
eating
at
a
time,
because
that
requires
four
Forks
and
then
you
have
like
one
left
over.
A
So
when
we
first
did
this
we're
going
over
mutexes
and
how
you
can
get,
you
can
kind
of
cause
a
staggering
effect
by
having
one
flaw.
So
first
start
eating
with
a
different
fork
if
one
of
them
starts
eating
with
the
right
fork
and
all
of
the
other
ones
start
with
their
left
fork,
then
you
have
this
kind
of
everyone.
It
kind
of
prop
propagates
which
one
is
allowed
to
eat
and
it
works
nicely,
but
it
only
allows
one
of
them
to
eat
at
a
time.
So
in
the
test
setup
I
didn't
have.
A
A
If
you're,
the
lapsed
philosopher
then
share
with
the
first
philosophers
left,
your
right
is
the
floss
less
phosphorus
or
the
first
philosophers
left
so
yeah
that
this
fixes
the
test
setup
and
then
you
can
see
the
deadlock.
So
what
I'm
going
to
do
at
the
bottom
of
the
screen
is
I'm,
going
to
run
the
with
using
the
the
st.
the
same
way.
We
would
do
it
with
a
simple
mutex,
we're
using
channels
as
mutexes
here,
I'm
gonna
do
the
same
thing
and
we're
going
to
see
it.
Hopefully,
deadlock.
A
442
for
you,
so
these
are
the
pointer
addresses
for
each
fork.
So
each
fork
is
a
channel.
A
channel
is
a
reference
type
and
go
and
we're
looking
at
the
address
to
keep
an
eye
to
know
which
exact
fork
we're
dealing
with
here.
So
we
see
here
that
one
picked
up
40
to
40,
so
the
other
person
at
the
table,
who
would
pick
up
that
same
fork
would
be
number
ones
right
is
twos
left.
A
So
if
we
look
at
two,
let's
see
here
two
picked
up
right:
did
you
pick
up
left
yeah,
there's
two
there's
one
I
think
what's
happening
here
is
that
this
one
is
not
able
to
pick
up
the
the
fork,
because
two
already
has
it:
I
actually
have
the
log
printed
out
before
it.
So
we
have
a
deadlock,
condition,
I'm
gonna
go
over
the
test
and
why
it's
failing
and
we'll
fluff
it
up
a
bit
get
nice
and
working
well.
A
So
the
first
thing
I'm
going
to
do
is
show
you
how
the
channel
works
as
a
mutex.
We
went
over
this
last
week,
so
this
is
a
bit
of
a
rehash.
So
hopefully
this
isn't
too
too
redundant.
So
in
go
a
channel.
Is
it's
like
a
queue
you
put
something
in
and
it
gets
taken
out
from
the
other
end
and
you
can
have
a
queue,
that's
of
zero
size.
So
when
you
have
a
queue
of
zero
size,
that
means
when
you
put
something
in
there
has
to
be
someone
else
pulling
something
out.
A
So
what
we
do
is
we
create
a
queue
of
size
one.
So
we
can
fit
one
thing
inside
of
it
and
we
use
that
as
a
way
of
marking
that
we
have
control
of
an
ax
of
a
resource.
So
normally
we
use
mutexes
to
do
this,
where
we
walk
in
unlock
a
critical
zone,
but
you
can
do
the
same
thing
with
the
channel.
The
nice
thing
about
channels
is
that
you
can
actually
choose
to
wait,
one
thing
or
another.
You
can
have
multiple
events
that
you're
waiting
for
can.
C
A
Know
you,
don't
you
don't
need
a
mutex
to
do
that,
so
the
the
way
that
the
channels
work
is
that
they're
thread
safe
and
you're
designed
for
synchronizing
to
go
routines.
So
you
have
to
go
routines
and
then
there's
a
point
in
the
go
routine,
where
they're
both
trying
to
communicate
on
the
same
channel.
They
sync
up,
even
though
they're
different
phases
of
their
execution,
one
will
just
be
blocked
until
the
other
one
gets
at
a
point
to
where.
C
A
Is
exactly
okay,
yeah
yeah,
so
it
it's
kind
of
it
seems
a
little
counterintuitive,
because
when
you
think
of
concurrency
and
parallelism
you're
like
I
want
these
to
run
independent
of
each
other,
but
every
once
in
a
while.
You
need
to
have
a
synchronization
event
where
they
both
stop
and
lock
at
some
position
and
exchange
information
and
then
proceed
independently.
So
the
way
we
get
around
that,
though,
because
right
now
the
way
we're
using
it
to
cheat
and
use
it
as
a
mutex,
we
have
to
make
it
a
size
of
one.
C
C
It's
like
it's,
it's
sort
of
like
a
way
of
doing
forking
without
having
to
fork.
You
can
do
an
in
process.
The
other
end
will
just
sort
of
sit
and
wait
and
listen
until
there's
work
to
be
done
and
don't
have
to
deal
with
that
can
click
the
actual
synchronization
between
the
two.
It
you
create
a
queue
of
a
size.
One
you
set.
You
start
the
channel.
The
other
side
of
the
channel
is
like
okay.
I
know.
You
want
me
to
do
work,
there's
no
work
to
be
done
here.
C
A
A
If
you
try
to
push
data
into
a
channel
and
there's
not
something
on
the
other
end,
you'll
deadlock,
your
thread
because
you're
the
only
one
communicating
on
this
channel,
so
what
you
can
do
is
you
can
give
it
a
size
and
by
giving
it
a
size,
you
can
put
something
in
there
and
it
doesn't
have
to
be
someone
on
the
other
end.
You
can
actually
pull
it
out
yourself.
So
in
that
case
it's
just
like
a
regular
slice
or
a
regular
queue
that
has
nothing
to
do
with
concurrency
yeah.
A
So
it's
sometimes
people
use
queues
as
a
way
to
like
handle.
Like
pressure
from,
like
you
have
a
lot
of
requests
coming
in
and
you
want
them
to
buffer
up
in
memory,
because
you
know
you
don't
have
enough,
you
have
a
concurrency
limit
that
doesn't
allow
you
to
service
every
one.
You're
like
okay,
I'll
use,
some
of
that
memory.
I
have
available
to
actually
queue
these
up
in
memory
and
then,
when
I
have
a
worker
available
to
pull
it
off.
C
A
Yeah
so
I'll
show
you
how
that's
actually
declared
so
in
our
test
setup.
The
way
we
do
that
is,
we
say
we
make.
We
want
to
make
a
struct
or
I
sorry
a
channel
of
empty
strokes
of
size,
one
so
that
one
right
there,
that's
the
critical
part,
if
you
just
omit
it
when
you
have
a
normal
queue
and
typically
you
want
to
work
with
a
queue
of
size:
zero,
because
that
lets.
A
You
know
that
everything
is
working
in
your
program
really
well,
if
you
put
in
these
buffers
that
are
not
needed
or
they're
like
auxilary,
you
know
they're
just
kind
of
there,
because
they're
nice
to
have
that
won't
make
certain
concurrency
problems
obvious
in
your
program.
So
usually
you
want
to
have
a
cube
size
zero
unless
it
deadlocks
you
in
certain
situations
like
it.
Doesn't
this
problem
mm-hmm?
Okay,
so
on
the
right
hand,
side
here
what's
happening
is
that
we
create
all
the
philosophers
we
create
all
their
Forks.
A
Their
forks
are
all
channels,
and
then
what
we
do
here
is
we
we
signal
to
the
philosophers.
We
want
you
to
start
so
just
going
over
again
what
this
is.
We
have
a
channel
and
that
channel
is
just
it's
a
size
zero
because
we're
actually
not
going
to
put
anything
in
it.
What
we're
gonna
do
is
before
the
the
workers
start.
We're
going
to
close
that
channel
and
closing
a
channel
is
a
way
of
broadcasting
an
event
to
all
the
listeners.
So
every
thread
are
sorry.
A
Every
every
philosophers
go
routine
is
waiting
for
the
start
of
it.
So
when
I
close
it
on
line
41
that'll
signal
to
all
of
them
to
roughly
start
at
about
the
same
time,
and
that's
because
there's
some
latency
in
the
scheduler
forgetting
a
go
routine
started.
So
we
don't
want
them
to
be
too
staggered
where
one
philosopher
just
does
all
its
work
before
there's
a
chance
to
have
contention
with
the
other
workers.
That's.
A
A
A
A
So
what
I'm
gonna
do
right
here
is
I'm,
going
to
make
a
quick
fix,
so
we're
we're
telling
the
worker
that
we
want
you
to
run
five
times
and
we're
also
providing
the
waiter
and
I'll
get
to
the
waiter
in
a
little
bit
for
right
now.
I
just
want
to
demonstrate
the
problem
with
the
naive
approach
so
over
here.
What
we're,
having
is
each
philosopher
and
I'll,
go
over
the.
A
What
a
philosopher
is
a
philosopher
is
just
an
ID
number,
so
we
can
keep
track
of
them
and
then
the
left
and
right
fork,
which
are
represented
by
Struck's
or
channels,
trucks,
empty
channels,
trucks
and
then,
when
we
go
to
the
loop
here,
the
loop
that's
trying
to
run
every
so
often.
So
it's
some
on
the
bottom.
You
can
see
that
that
test
finally
died.
It
must
have
been
ten
minutes
or
something
it
died.
I'm.
C
A
C
A
C
A
A
A
So
what
we're
gonna
have
here
is
the
philosophers:
gonna
try
to
pick
up
their
left
and
then
pick
up
the
right
once
they
have
both
forks
they're
gonna
eat
and
we're
gonna.
We're
gonna
make
them
just
sleep
for
3
seconds
to
represent
work,
that's
being
done
and
then
we're
gonna,
say:
okay,
we're
gonna
increment
this
counter
to
say
that
we
had
one
successful
eating
loop.
You.
A
You
got
you
ate
your
meal
and
now
you're
ready
to
think,
because
we're
always
transitioning
from
being
hungry
to
eating
to
thinking.
So
the
philosopher
will
put
down
their
left
fork
and
then
put
down
their
right
fork
and
then
they'll
think
right
here,
I'm
thinking
it's
just
trans
transitioning
to
another
state,
but
as
we
saw
over
here
it
it
crapped
out,
there
was
a
deadlock
because
two
philosophers
were
going
for
the
same
fork.
I
think
it
was
one
in
two
that
we're
going
for
the
same
fork
and
that's
not
good.
A
B
C
C
A
B
C
A
A
A
A
And
do
we
already
find
a
deadlock?
We
might
have
found
a
deadlock
already,
so
zero
is
reaching
for
right,
which
is
three
six
zero
right
here
and
then
so.
Zero
is
sharing.
The
right
with
left
left
is
reaching
for
four
three
six
zero.
You
see
that
right
here,
one
is
stuck
because
it's
trying
to
pick
up.
C
B
A
Time
the
emojis
are
so
easy
to
identify
in
the
log
output.
Just
put
a
like
a
really
unique
emoji,
you
can
spot
it
like
left
is
picking
up
heart,
emoji
or
you
know,
is
picking
up.
Poop
emoji
like
you'll,
be
able
to
spot
it
like
immediately
so
I'll
do
that
next
time.
Let
me
put
that
idea.
Yeah
I
was
doing
that
with
another
one
of
the
I.
Don't
know,
if
was
dining
philosophers,
or
if
it
was
the
binary
search,
but
I
was
putting
in
a
lot
of
emojis
to
make
it
easy.
C
C
A
So
we're
stuck
here
and
I
want
to
go
over
how
we
can
try
to
resolve
this
using
a
more
flexible
approach
like
right
now
we
have
one
person
picking
up
the
left
and
one
person
pick
our
s,
sorry,
everyone's
picking
up
the
left
and
then
the
right
and
it's
it
becomes
problematic
because
everyone's
doing
the
same
thing,
they
have
the
same
strategy.
So
what
we
can
do
is
we
can
have
well.
We
can
do
one
of
two
things
we
can
have.
A
A
So
what
we
can
do
here
is,
we
can
say
we're
gonna
try
to
reach
for
the
left
only
if
we
have
the
waiters
blessing,
so
the
waiter
is
gonna
say
we're
gonna,
try
to
put
a
token
into
the
waiters
plate
and
there's
only
spots
for
two
tokens
and
so
the
way
we
know.
That
is
because
we
created
a
channel
that's
of
size
two.
So
once
we
fill
up
this
once
we
fill
up
the
the
the
tray
the
plate
that
the
waiters
holding
we
can't
put
more
stuff
on
it.
A
So
that
rate
limits
us
to
two
at
a
time.
So
we're
gonna
try
to
put
something
in
on
to
the
waiters
plate
and
then
once
we're
able
to
we're
gonna,
try
to
do
everything
and
then
we're
going
to
at
the
end
of
this
after
we're
thinking
then
or
actually
I'm.
Sorry,
when
we're
done
eating
know
when
we're
done
thinking
we're
going
to
release
control
of
that
by
taking
back
our
token
from
the
waiter.
A
A
That
they're
able
to
proceed
and
I
have
some
notes
here
on
how
much
time
they
should
take.
We
have
a
three
second
eating
time.
We
have
we're
doing
it
five
times
times
five
philosophers
three
seconds:
each!
That's
seventy
five
seconds,
I'm
gonna,
throw
this
down
a
little
bit
actually
because
this
is
too
much
time
yeah
what
to
keep
it
at
45,
so
each
one's
gonna
run
three
times:
okay,
so
the
fastest.
We
can
theoretically
finish.
A
This
problem
is
in
twenty
two
and
a
half
seconds
if
we
paralyze
work
with
two
philosophers
eating
at
a
time,
because
each
philosopher
five
times
five
philosophers
three
seconds
each
45
seconds.
So
if
we,
if
we
want
to
set
a
timeout
for
this
test,
we
can
just
set
it
at
maybe
a
little
bit
over
twenty
two
point:
five
to
allow
for
inefficiencies
and
things
we
can't
control,
compile
time
that
sort
of
stuff.
So
we
said
it
25
seconds
I!
A
Think
we
already
passed
25
seconds,
we've
hit
a
deadlock,
so
it's
not
enough
for
the
waiter
to
come
in
and
tell
the
the
various
philosophers
which
one
can
come
and
go
because
the
waiter
is
is
a
dumb
waiter.
The
waiter
is
basically
relying
on
the
go
runtime
here
to
randomly
and
deterministically
assign
an
empty
slot
to
a
philosopher.
So
we
don't.
We
don't
have
any
insight
to
how
that's
happening.
That's
just
like
a
black
box
to
us.
We,
we
don't
know
how
the
go
runtime
is
making
that
decision.
A
So
the
waiter
might
be
seating.
It
might
be
allowing
two
philosophers
that
sit
next
to
each
other
to
go.
That's
within
the
realm
of
possibility,
and
so
when
that
happens,
we
have
we
end
up
with
two
philosophers
that
deadlock
each
other
and
then
they
never
get
to
the
bottom
here
where
they
can
release
that
that
spot
on
the
waiters
plate.
So
this
isn't
and
this
this
might
succeed.
Some
of
the
time
like
if
I
run
this
again
and
what
I'll
do
to
show
that
this
can
some
work
is
all
make
a
really
short
work
time.
A
Let's
do
a
millisecond
right
and
then
we'll
try
it
again
and
we
might
be
able
to
get
through.
It
looks
like
we
got
a
deadlock
because
if
we
just
so,
if
we
were
lucky
enough
that
the
Wayner
always
ran
the
two
people
opposite
of
the
table
from
each
other,
then
we
would
get
the
we
would
get
a
success
criteria,
but
it
doesn't
look
like
that.
A
The
odds
of
that
happening
are
very
good
and
we
have
anyone
who
knows
probability,
theory
who
could
tell
us
what
are
the
chances
that
the
two
people
selected
each
of
the
three
turns
or
whatever
out
of
five
people.
It
doesn't
seem
like
it's
by
good
of
odds.
Maybe
if
I
ran
this
test
a
hundred
times,
we'd
see
some
wins
in
there.
A
What's
that
for
science
yeah
for
science
yeah,
it's
it's
not
it's
not
happening
so
yeah
we're
we're
deadlocked
here,
the
waiters
not
intelligent
enough.
So
what
we're
gonna
do
is
we're
gonna
program
in
a
strategy
into
the
the
philosophers
where
the
philosophers
are
going
to
you
take
advantage
of
how
channels,
let
us
opportunistically,
select
the
available
ready,
Channel
and
use
that
to
be
able
to
pick
the
best
philosopher
and
then,
if
the
philosopher
is
the
the
worst
philosopher
is
chosen,
they
will
give
up
control
you'll
concede
control
so
that
another
philosopher
can
try.
A
Let's
try
that
so
I'm
gonna
put
this
back
to
the
value
once
before,
and
then
we're
going
to
I'm
gonna
show
you
where
this
code
is
done.
So
here's
a
select
statement,
and
so
the
Select
statement
is
where
we
select
against
the
different
channels.
So
we're
gonna
try
to
select
against
the
left
fork
and
then
we're
gonna
try
against
the
right
fork
or
sorry
we're
gonna,
try
it
both
at
the
same
time.
So
that's
what
this
statement
is
saying.
A
It's
saying
I
want
you
to
try
putting
a
token
into
the
left,
channel
and
the
right
channel
and
if
you
can't
put
it
into
either
of
those,
then
I
want
you
to
run
this
code,
which
is
just
to
abort.
So
if
you
abort
you're
gonna
return
false,
so
this
function
right
here,
try
what
it's
saying
is:
I'm
gonna,
try
and
if
I'm
successful
it's
going
to
return
true,
if
I,
try
and
I'm
not
successful,
it's
returning
false.
A
So
if
we
were
able
to
successfully
pick
up
the
left
fork,
then
we're
gonna
say
the
other
fork
that
we
need
to
pick
up
is
the
right
and
we're
going
to
say
that
before
the
end
of
this
function,
we
need
to
release
control
of
that
left
fork
and
the
way
this
is
gonna
work
is
that
the
defer
is
basically
a
what's
it
called
it's
a
first-in
first-out
or
no
yeah,
first,
in
first
out
queue.
A
A
Run
until
the
function
returns,
yeah
so
that
that's
actually
a
common
program
in
a
state
to
like
you'll,
see
people
put
defer
statements
into
for
loops
and
they
expect
it
to
run
at
the
end
of
the
for
loop.
But
then
what
they'll
do
in
addition
to
the
problem?
There's
two
complications
that
happen.
First,
there's
the
the
issue
that
you
think
that
it'll
run
at
the
end
of
the
for
loop,
but
then
also,
you
might
have
a
shared
variable
in
your
for
loop
and
that
shared
variable.
A
If
you
call
defer
five
times
and
you
expect
five
defers
to
get
called,
but
it's
all
getting
called
on
the
same
variable
instead
of
the
value
that's
being
assigned
to
that
variable.
That
becomes
a
problem.
So
yeah,
there's,
there's
tricky
things
when
you
call
defers
inside
of
different
kinds
of
blocks
like
select
blocks
and
for
for
loops
and
stuff.
A
A
A
I
don't
want
to
eat
anyway,
and
just
let
the
person
next
to
us
try
it,
which
is
actually
a
polite
thing
to
do
right
like
because
normally
these
philosophers
they're
very
stubborn,
and
they
don't
want
to
they
don't
want
to
share
that
fork
once
they
have.
The
fork
they're
like
I,
have
to
have
the
right
fork.
A
This
philosopher
that
we're
designing
here
is
a
much
more
flexible
philosopher
where
they
are
able
to
say:
okay,
I,
don't
want
everyone
to
lose
so
I'm
just
going
to
give
up
control
of
that
fork
and
then
just
like
the
other
fork,
we
have
to
push
on
to
the
the
Q.
We
have
to
push
on
a
release
of
that
fork,
so
we
empty
that
fork
out
and
if
we
are
able
to
do
all
of
this,
we
return
true
and
now
you
can
see
over
here.
A
A
A
Try
this
out,
oh,
and
also
we
have
this
thing
about
the
the
waiter.
So
here
what
we're
doing?
We
actually
don't
need
a
select
statement
here.
So
I'll
show
you
why
the
select
statements
only
really
needed
if
you
want
to
have
an
alternative
action
like
another
channel,
you
listening
on
or
a
default
thing,
so
we
don't
need
that
because
whoops,
we
don't
need
that,
because
we're
going
to.
A
A
Here,
yeah:
that's
what
we
want
to
do,
okay,
so
we
have
the
old
code
commented
out,
and
then
we
have
this
new
code
where
we're
just
waiting
for
a
chance
to
put
something
on
the
waiters
plate.
We're
gonna
try
if
we're
successful,
we're
going
to
decrement
the
count
and
then
we're
gonna
release
control
of
that
the
waiter
by
taking
our
token
back
from
their
plate.
A
A
Shouldn't
it
shouldn't
really
impact
the
logic
here.
We
can
try
doing
that
too.
We
can
add
a
random
time,
so
I
don't
think
it'll
impact
the
the
logic
as
far
as
the
way
the
waiter
is
coordinating
them
and
how
they're
picking
up
and
the
forks
and
stuff
I
think
what's
going
to
happen,
is
we're
just
gonna
at
what
what's
I
guess.
What
obvious
to
everyone
else
is
that
the
people
who
take
the
longest
are
gonna
determine
how
long
this
takes
right.
The.
B
A
C
Was
something
that
you
said,
that's
sort
of
sticking
with
me
and
like
where
go
has
to
decide
which
go
routine
to
yield
execution
to
and
I'm
just
wondering?
How
does
it
do
that?
Does
it
gives
I
keep
track
of
the
time
that
each
go
routine
is
spending
and
then
take
like
an
average
of
that
and
based
on
that
prioritize
I?
Don't.
A
That's
a
good
question:
that's
a
good,
follow
I've
seen
some
there's
a
lot
of
articles,
the
in-depth
articles
that
people
write
about
the
scheduler
and
how
it
makes
decisions,
but
I,
don't
think
it
really
cares
how
fair
it
is
within
reason.
Maybe
it
does
to
a
certain
extent,
but
that's
a
good
follow-up
question.
A
A
A
There's
there's
some
interesting
things
that
the
the
go
maintain
errs
have
done
to
like
make
people
respect
the
spec
and,
like
one
of
the
things,
is
the
way
you
iterate
over
a
map
order.
Oh
yeah,
over
map
key
values.
So,
if
you
iterate
over
a
map,
the
order
of
that
you
iterate
over
the
keys
is
randomized.
A
A
Because
you
might
think
oh
I've
seen
it
happen
before,
where,
if
I
put
keys
in
a
certain
order,
if
I
iterate
over
it,
they
come
out
that
same
order,
and
then
people
make
all
these
assumptions
over
the
years.
And
then
someone
makes
a
change
to
the
language
that
was
never
stated
in
the
spec
right
and
they
were
dependent
on
that
unspecified
behavior,
and
so
that
becomes
a
huge
issue.
A
C
A
That
that's
an
important
thing
to
note
about
I
was
just
listening
to
a
podcast
where
the
two
of
the
creators
we're
talking.
The
early
founding
creators
were
talking
about
how
they
developed
the
spec
before,
like
anything
else
the-
and
that
was
a
really
important
part
of
the
language,
because
some
languages-
they
don't
formalize
their
spec
and
then
it
makes
a
lot
of
other
things
harder
to
do,
but
they
wrote
the
spec
first
and
then
they
wrote
a
compiler
like
sometimes
you'll
have
a
compiler.
That's
the
reference
for
the.
A
A
It's
horrific
to
like
even
think
about
looking
at
their
spec
right,
like
I,
don't
want
to
know
what
Java
looks
like
or
C++
the
modern
C++
like
there's
so
many
features
in
there,
but
go
is
so
minimal
and
they've
done
a
good
job
of
keeping
it
that
way
that
it's
it's
fairly
friendly
to
approach.
So
it's
it's
pretty
nice
so
as
far
as
yeah
no
problem.
C
A
A
See
how
that
goes
so
be
one
two
or
three
and
let's
actually,
let's
print
what
this
is
so
yeah.
B
A
A
A
C
A
A
C
A
No,
no,
this
is
what
I
need.
I
need,
the
more
people
that
yell
at
me,
the
better
the
code
ends
up
being
so
alright,
we
got
a
forty
seven
where's,
the
air,
but
we
got
an
extra
parenthesis
or
looks
like
there's
an
extra.
A
B
A
A
A
C
C
A
The
go
runtime
did
a
lot
of
work
for
us
like
if
we
wanted
to
actually
make
you
know
the
philosophers
give
up,
control
the
forks
or
only
choose
the
fork.
That's
available.
That's
a
lot
of
that's
a
lot
of
stuff
to
write
in
other
languages,
especially
lower
level
languages.
So
the
the
concurrency
primitives
and
the
the
language
features
and
go
for
concurrency
are
very
high
level
like
they
allow
us
to
do.
A
lot
with
very
little
code
like
go
is
usually
a
pretty
low-level
language,
especially
to
something
like
Ruby
or
Python.
A
C
A
So
I'm
gonna
get
rid
of
semaphore
here,
I
want
to
say
they
call
it
like
a
manager
or
coordinator
coordinator,
yeah,
okay,
yeah
I.
Think
it's
a
coordinator,
so
you
have
a
coordinator
who
manages
access
to
the
resource
and
that's
where
the
semaphore
is
come
in
so
you're
essentially
rate-limiting
it,
but
then
we're
also
making
it
we're
adding
intelligence
to
the
waiter
by
using
the
go
runtime
with
those
select
statements.
So
like
it,
the
the
waiter
is
dumb
enough
to
see
tell-tell
two
people
sitting
next
to
each
other
to
proceed.
A
So
we
add
we
we
compensate
for
that
with
the
Select
statements
where
we
say:
okay,
if
I
don't
have
access
to
this
resource
just
give
up
and
let
someone
else
try
so
yeah.
We
we
make
the
Philosopher's
less
greedy
to
make
up
for
the
lack
of
intelligence
and
the
waiter,
so
we
could
have
got.
We
could
have
gone
another
way
with
that
and
we
could
have
made
the
waiter
smart
enough
to
never
pick
two
people
that
two
philosophers
that
are
sitting
next
to
each
other.
A
B
A
I
think
that's
what
it's
called
is
like
a
coordinator.
This
is
the
same
page.
I
was
just
looking
at
I'm
trying
to
find
that
here
it
is
the
Ron
Swanson's.
This
is
the
best
illustration.
So
if
we
go
to
semaphores
yeah,
so
here's
that
they
introduced
the
waiter
right
do
the
other
ones
yeah.
This
is
the
first
one
where
they
do
that.
So
the
waiter
is
a
waiter
analogy.
A
Yeah
no
worries
the
more
talking
the
better
like
when
it's
just
me
like
stumbling,
then
it's
not
as
fun.
So
the
more
everyone
jumps
in
the
better.
So
we
were
talking
last
week
about
going
over
some
more
sink,
primitives
and
I
just
remembered
that
another
time
we
were
doing
this,
we
were
talking
about
error
handling,
so
I
was
thinking.
A
Maybe
a
nice
thing
to
do
next
time
would
be
to
handle
errors
with
concurrency
there's
some
cool
stuff
that
is
in
the
the
go
X
repos
X
repos
are
like
kind
of
like
auxilary
repos
that
are
secondary
to
the
standard
library
there's
some
cool
stuff
in
there
for
handling
errors.
Concurrently
and
there's
some
stuff.
A
We
can
do
with
the
standard
library
too,
and
then
there's
proper
error
handling,
because
there's
recently
and
go
1.13
they've
introduced
the
idea
of
air
wrapping
where
you
can
wrap
an
air
with
another
air
to
add
context:
oh
yeah,
so
we
can.
We
can
also
discuss
best
practices
while
showing
the
concurrency
stuff,
so
I'm
gonna
try
to
come
up
with
something
I,
don't
know
if
I'll
be
able
to
do
it
this
next
week,
but
maybe
the
following
week,
we'll
look
at
doing
air
handling
with
concurrency
and
maybe
I
can
work
it
into
the
dining
philosophers.