Bonjour à tous!
Je découvre la programmation multi threade, et je me suis dit que le mieux était d'essayer la lib pthread, en faisant un "producteur-consommateur" (un thread essaye d'écrire dans un tableau, un autre thread essaye de lire ce tableau).
Vu que c'est la premiere fois que je vais ça, je voulais savoir si la logique et la méthode était bonne, si l'architecture du programme était logique, et enfin si vous auriez fait pareil ou pas (pour améliorer ma technique).
(Une fois mon programme écrit, je me suis inspiré de http://franckh.developpez.com/tutoriels/posix/pthreads/ pour corrigé certains problèmes)
Fonctionnement :
Pour cela, j'ai un main, qui lance 2 threads (puis fait un sleep 2): l'un qui lit dans le tableau nommé i_tab de taille RESOURCE_SIZE, et l'autre qui écrit dans ce tableau.
Le thread producteur, s'il est exécuté, boucle à l'infini et remplis le tableau s'il y a assez de place, et le thread consommateur libère de la place dans le tableau s'il n'est pas vide.
L'algo que j'utilise pour le thread consommateur :
1-Rentrer en section critique
2-S'il y a des choses à lire dans le tableau:
En lire iNb (dans mon cas c'est toujours 1, donc en lire 1!).
Envoyer un signal comme quoi le tableau n'est pas rempli (car j'ai lu 1 élement!)
Sortir de section critique.
Recommencer en 1.
S'il n'y a rien à lire dans le tableau:
Se mettre en attente du thread producteur qui remplira le tableau
Sortir de section critique.
Mon code pour le thread consommateur :
Je mets uniquement la fonction de lecture (consommateur) (le producteur ayant la même architecture, sauf qu'avant d'écrire, on teste s'il reste de la place dans le tableau au lieu de tester si le tableau est vide!), et je ne mets pas le main non plus, ça ne sert à rien, car je fais juste:
1-lancer le thread lecture;
2-lancer le thread écriture;
3-sleep(2);
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 /*! \param[in] iNb: nb data to read * \param[in] psResource (struct containing mutex, table and actual position in table) * \return nb of elements read */ int thread_read(int iNb, resource_s *psResource){ int indi; /*Go in critical section*/ pthread_mutex_lock(&(psResource->mutex)); fprintf(psResource->fid, "thread read: critical section in\n"); /*If the table is not empty*/ fprintf(psResource->fid, "thread read: position=%d size asked=%d table size=%d\n", psResource->i_pos, iNb, RESOURCE_SIZE); if(psResource->i_pos - iNb >= 0){ //ICI, je regarde s'il y a des choses à lire dans le tableau. Si oui, lire, iNb éléments, sinon il faut endormir le thread. i_pos est la position actuelle dans le tableau, cad 0 si la tableau est vide, RESOURCE_SIZE-1 s'il est plein, etc... psResource->i_pos -= iNb; //ICI, je dis que j'ai lu des données for(indi=0; indi < iNb; ++indi){ psResource->i_tab[psResource->i_pos - indi] = 0; //Ici, je remets les élements lu à 0 } fprintf(psResource->fid, "thread read: nb elem readed=%d, actual position=%d\n", indi, psResource->i_pos); fprintf(psResource->fid, "thread read: send signal\n"); pthread_cond_signal(&(psResource->cond1)); //Ici, je signal au thread producteur que j'ai lu des données et donc que le tableau a de la place libre fprintf(psResource->fid, "thread read: critical section out\n"); pthread_mutex_unlock(&(psResource->mutex)); }else{ /*Sleep*/ fprintf(psResource->fid, "thread read: can t read, sleep\n"); pthread_cond_wait(&(psResource->cond2), &(psResource->mutex)); //ICI, j'attends que le thread producteur remplisse le tableau fprintf(psResource->fid, "thread read: critical section out\n"); pthread_mutex_unlock(&(psResource->mutex)); /*unlock mutex*/ } return iNb; }
Qu'en pensez vous? Est-ce une bonne méthode? Une bonne logique? Auriez-vous fait pareil?
Est-ce que je peux avoir (avec cette architecture) un blocage (genre les 2 threads attendent la même conditions...).
En fin, ma derniere question:
est-ce normal de mettre pthread_cond_wait dans une section critique?
En effet, dans mon cas, je ne comprends pas pourquoi ça marche, je pensais que ça ferai:
[dans le thread consommateur]
1-entrer en section critique [mutex]
2- si il n'y a rien à lire, pthread_cond_wait
3- alors, le thread s'endort et l'ordonnanceur passe au thread producteur.
4- le thread producteur essaye de passer en section critique, mais il ne peux pas, car mutex n'a pas été relaché auparavant.
Bon, vu que le programme fonctionne, ce que je dis ci dessus est faux, mais pourquoi?
Ca fait beaucoup de questions, j'espère ne pas vous ennuyer avec.
En tout cas, si ce sujet vous interesse et que vous voulez bien répondre à mes questions, et bien merci beaucoup!
Cordialement,
morpheusmg
Partager