TD 6

Vendredi 28 février 2003

On désire créer un petit agenda partagé (sur un mois), avec accès concurrent. Pour cela, nous allons définir un serveur utilisant des co-processus. Les clients effectueront des opérations sur l'agenda par l'intermédiaire d'appels de fonctions distantes en OCaml.

1  Un serveur à co-processus

Écrire une fonction establish_thread_server qui fait la même chose que la fonction establish_concurrent_server du td précédent mais utilisant des co-processus à la place de processus. Tester votre fonction en utilisant le serveur de mise en majuscule du td précédent.
(corrigé)

2  Exclusion mutuelle

Écrire une fonction establish_fixed_thread_number_server, comparable à la fonction précédente, qui lance au démarrage un nombre fixé de co-processus plutôt que de les lancer au fur et à mesure des connexions. Pour cela, tous les co-processus acceptent de façon concurrente les connexions. Pour assurer qu'un unique co-processus acceptera une connexion, l'appel à accept est protégé par un mutex.
(corrigé)

3  Un écrivain, plusieurs lecteurs

Le serveur utilisant des co-processus , il faut faire attention à assurer la cohérence de l'agenda. Pour cela, on impose qu'à tout instant, il y ait un unique écrivain ou (exclusif) plusieurs lecteurs en train de manipuler l'agenda.

Écrire des fonctions write_protect: control -> ('a -> 'b) -> 'a -> 'b et read_protect: control -> ('a -> 'b) -> 'a -> 'b qui permettent d'assurer la condition précédente pendant l'exécution de la fonction passée en argument.

Pour cela, on pourra utiliser le type et la fonction suivants.
      
type control =
    { mutex : Mutex.t;
      write_enable : Condition.t ;
      mutable readers : int };;
let create () =
  { mutex = Mutex.create ();
    write_enable = Condition.create();
    readers = 0;
 };;
(On pourra utiliser la fonction delay pour simuler que l'écriture ou la lecture prennent un certain temps, afin de pouvoir observer les attentes sur le mutex.)
(corrigé)

4  Coté serveur

Maintenant que nous avons défini toutes les fonctions utilitaires dont nous aurons besoin, nous définissons des types pour décrire l'agenda et les opérations que le client pourra demander au serveur d'effectuer :
      
type event = {start : intfinish : intinfo : string }
type day = (string*eventlist;;
type agenda = day array;;

type operation =
Get_agenda  (** demander les informations de tout l'agenda *)
Get_day of int (** demander les informations sur une journée *)
Add_event of string * int * int * int * string
     (** (nom, jour, heure début, heure fin, info) ajouter une entrée, le
         nom droit être unique le jour donné  *)
Delete_event of string * int
     (** (jour, nom) supprimer les informations de la journée donnée
        avec le nom donné *)
;;

type result =
  | Unit
  | Agenda of agenda
  | Day of day
  | Exception of exn
;;
Définir la fonction execute_query qui lit une opération depuis un descripteur passé en argument, l'effectue puis écrit son résultat dans le descripteur. Par exemple, si l'opération lu depuis le descripteur est Get_day, cette fonction lit le jour demandé dans l'agenda puis retourne le résultat qui sera soit de type Day si le jour demandé existe, soit de type Exception si une exception a été levée.
(corrigé)
Terminer le serveur.
(corrigé)

5  Coté client

Définir la fonction remote_query qui prend une operation, se connecte au serveur et fait exécuter l' operation par le serveur.
(corrigé)
Définir les fonctions get_day, get_agenda, add_event et delete_event qui effectuent les opérations correspondantes sur le serveur distant. L'adresse du serveur et le port sont des constantes dans le code.
(corrigé)
Écrire un programme client qui effectue des accès au calendrier. Par exemple, on pourra définir des suites d'appels aux fonctions distantes et lancer la suite dont le numéro est passé sur la ligne de commande.
(corrigé)



This document was translated from LATEX by HEVEA and HACHA.