Il suffit alors d'appeler ces fonctions en début et en fin de boucle d'un philosophe.
#
let
entrer
,
sortir
=
let
n
=
ref
0
in
let
m
=
Mutex.create()
in
let
c
=
Condition.create()
in
let
loc_entrer
()
=
Mutex.lock
m
;
while
not
(
!
n
<
4
)do
Condition.wait
c
m
done
;
incr
n
;
if
!
n
>
1
then
Printf.printf
"%d philosophes sont a table\n"
!
n
else
Printf.printf
"%d philosophe est a table\n"
!
n;
flush
stdout;
Mutex.unlock
m
in
let
loc_sortir
()
=
Mutex.lock
m
;
decr
n
;
Mutex.unlock
m
;
Condition.broadcast
c
in
loc_entrer
,
loc_sortir
;;
val entrer : unit -> unit = <fun>
val sortir : unit -> unit = <fun>
Attention, cette solution supprime les inter-blocages, mais pas les famines. Pour résoudre ce dernier problème, on peut soit se fier au hasard en introduisant un délai d'attente en aprés la sortie d'un philosophe, soit gérer explicitement une file d'attente.
# letphilosophe
i
=
let
ii
=
(i
+
1
)mod
4
in
while
true
do
Printf.printf
"Le philosophe (%d) se pointe\n"
i
;
entrer
()
;
mediter
3
.
;
Mutex.lock
b
.
(i);
Printf.printf
"Le philosophe (%d) prend sa baguette gauche et medite encore un peu\n"
i;
mediter
0
.
2
;Mutex.lock
b
.
(ii);
Printf.printf
"Le philosophe (%d) prend sa baguette droite\n"
i
;
manger
0
.
5
;
Mutex.unlock
b
.
(i);
Printf.printf
"Le philosophe (%d) rend sa baguette gauche et commence deja a mediter\n"
i;
mediter
0
.
1
5
;
Mutex.unlock
b
.
(ii);
Printf.printf
"Le philosophe (%d) rend sa baguette droite\n"
i
;
sortir
()
;
Printf.printf
"Le philosophe (%d) se tire\n"
i
;
done
;;
val philosophe : int -> unit = <fun>
# classdistrib
()
=
object
val
mutable
n
=
0
val
m
=
Mutex.create
()
val
c
=
Condition.create
()
method
attendre
nc
=
Mutex.lock
m
;
while
(n
<=
nc)
do
Condition.wait
c
m
done
;
Mutex.unlock
m
method
prendre
()
=
Mutex.lock
m
;
n
<-
n
+
1
;
let
nn
=
n
in
Condition.broadcast
c
;
Mutex.unlock
m
;
nn
end
;;
class distrib :
unit ->
object
val c : Condition.t
val m : Mutex.t
val mutable n : int
method attendre : int -> unit
method prendre : unit -> int
end
#
method
private
reveil
t
=
let
dt
=
delai_attente_appel
/.
1
0
.
0
in
while
(Unix.gettimeofday()
<
t)
do
Thread.delay
dt
done;
Condition.signal
c
method
attendre_arrivee
()
=
let
t
=
Unix.gettimeofday()
+.
delai_attente_appel
in
let
r
=
Thread.create
self#reveil
t
in
Mutex.lock
m;
while
libre
&&
(Unix.gettimeofday()
<
t)
do
Condition.wait
c
m
done;
(try
Thread.kill
r
with
_
->
());
let
b
=
not
libre
in
(Mutex.unlock
m;
b)
# classaffich
(d
:
distrib)
=
object
val
mutable
nc
=
0
val
m
=
Mutex.create
()
val
c
=
Condition.create
()
method
attendre
n
=
Mutex.lock
m
;
while
nc
<
n
do
Condition.wait
c
m
done
;
Mutex.unlock
m
method
attendre_jusqu'a
n
t
=
Mutex.lock
m
;
while
(nc
<
n)
&&
(Unix.gettimeofday()
<
t)
do
Condition.wait
c
m
done
;
let
b
=
not
(nc
<
n)
in
Mutex.unlock
m
;
b
method
appel
(g
:
guichet)
=
Mutex.lock
m
;
d#attendre
nc
;
nc
<-
nc
+
1
;
g#set_nc
nc
;
Condition.broadcast
c
;
Mutex.unlock
m
end
;;
class affich :
distrib ->
object
val c : Condition.t
val m : Mutex.t
val mutable nc : int
method appel : guichet -> unit
method attendre : int -> unit
method attendre_jusqu'a : int -> float -> bool
end
#type bureau = { d: distrib; a: affich; gs: guichet array }
val delai_service : float = 4
val delai_arrivee : float = 2
val delai_guichet : float = 0.5
val delai_attente_client : float = 0.7
let
guichetier
((a
:
affich)
,
(g
:
guichet))
=
while
true
do
a#appel
g
;
Printf.printf
"Guichet %d appelle %d\n"
g#get_ng
g#get_nc
;
if
g#attendre_arrivee
()
then
g#attendre_depart
()
else
begin
Printf.printf
"Guichet %d n'attend plus %d\n"
g#get_ng
g#get_nc
;
flush
stdout
end
;
Thread.delay
(Random.float
delai_guichet)
done
;;
val guichetier : affich * guichet -> unit = <fun>
#val chercher_guichet : 'a -> < get_nc : 'a; .. > array -> int = <fun>
let
client_impatient
b
=
let
n
=
b
.
d#prendre()in
let
t
=
Unix.gettimeofday()
+.
(Random.float
delai_attente_client)
in
Printf.printf
"Arrivee client impatient %d\n"
n;
flush
stdout;
if
b
.
a#attendre_jusqu'an
t
then
let
ig
=
chercher_guichet
n
b
.
gsin
b
.
gs.
(ig)#arriver();
Printf.printf
"Le client %d occupe le guichet %d\n"
n
ig
;
flush
stdout
;
Thread.delay
(Random.float
delai_service)
;
b
.
gs.
(ig)#partir();
Printf.printf
"Le client %d s'en va\n"
n
else
Printf.printf
"Le client %d, las d'attendre, s'en va\n"
n
flush
stdout
;;
Characters 518-531:
This function is applied to too many arguments
# classproduit
(s
:
string)
=
object
val
nom
=
s
method
nom
=
nom
end
;;
class produit : string -> object val nom : string method nom : string end
classproduit
:
string
->
object
val
nom
:
string
method
nom
:
string
end
# classmagasin
n
=
object(self)
val
mutable
taille
=
n;
val
mutable
np
=
0
val
mutable
buffer
=
(
[||]
:
produit
array)
val
mutable
ip
=
0
(* Indice producteur *)
val
mutable
ic
=
0
(* Indice consommateur *)
val
m
=
Mutex.create
()
val
c
=
Condition.create
()
initializer
buffer
<-
Array.createn
(new
produit
"empty"
)
method
display1
()
=
let
i
=
ip
mod
taille
in
Printf.printf
"Ajout (%d)%s\n"
i
((buffer
.
(i))#nom)
method
deposer
p
=
Mutex.lock
m
;
while
(ip
-
ic+
1
>
Array.length(buffer))
do
Condition.wait
c
m
done
;
buffer
.
(ipmod
taille)
<-
p
;
self#display1()
;
ip
<-
ip
+
1
;
Mutex.unlock
m
;
Condition.signal
c
method
display2
()
=
let
i
=
ic
mod
taille
in
Printf.printf
"Retrait (%d)%s\n"
i
((buffer
.
(i))#nom)
method
prendre
()
=
Mutex.lock
m
;
while(ip
==
ic)
do
Condition.wait
c
m
done
;
self#display2()
;
let
r
=
buffer
.
(icmod
taille)
in
ic
<-
ic
+
1
;
Mutex.unlock
m
;
Condition.signal
c
;
r
end
;;
class magasin :
int ->
object
val mutable buffer : produit array
val c : Condition.t
val mutable ic : int
val mutable ip : int
val m : Mutex.t
val mutable np : int
val mutable taille : int
method deposer : produit -> unit
method display1 : unit -> unit
method display2 : unit -> unit
method prendre : unit -> produit
end
Les indices ic et ip sont manipulés respectivement par les producteurs et les consommateurs. L'indice ic donne l'indice du dernier produit pris et ip celui du dernier produit stocké. Le compteur np donne le nombre de produits en stock. L'exclusion mutuelle et la mise en attente des producteurs et des consommateurs seront gérées par les méthodes de cette classe.
classmagasin
:
int
->
object
val
mutable
buffer
:
produit
array
val
c
:
Condition.t
val
mutable
ic
:
int
val
mutable
ip
:
int
val
m
:
Mutex.t
val
mutable
np
:
int
val
taille
:
int
method
deposer
:
produit
->
unit
method
prendre
:
unit
->
produit
end
->
string
->
unit.
# letconsommateur
mag
na
=
while
true
do
let
p
=
mag#prendre()
in
Printf.printf
"Le consommateur %s prend le produit %s\n"
na
p#nom
;
flush
stdout
;
Thread.delay(Random.float(
3
.
0
))
done
;;
val consommateur :
< prendre : unit -> < nom : string; .. >; .. > -> string -> unit = <fun>
->
string
->
unit.
# letproducteur
=
let
num
=
ref
0
in
let
creer_produit
()
=
let
p
=
new
produit(
"lessive-"
^
(string_of_int
!
num))in
incr
num
;
p
in
function
mag
->
function
nm
->
while
true
do
let
p
=
creer_produit
()
in
mag#deposer(p)
;
Printf.printf
"Production de %s\n"
p#nom
;
flush
stdout
;
Thread.delay
(Random.float
(
1
.
0
))
done
;;
val producteur : < deposer : produit -> '_a; _.. > -> '_b -> unit = <fun>