non il faut utiliser un objet condition aussi
Version imprimable
je ne pense pas que ce soit bon parce que ce n'est pas fait d'une maniere transactionelle, plusieurs threads peuvent etre dans une loop et acquerir un peu du semaphore ... ce qui n'est pas bon a mon avis, il doivent acquerir l'ensemble des resources demandées sinon rien ... non ?
EDIT: OK laisse tomber j'ai tort :aie:
oui, t'as raison. Il faut pouvoir déclencher un signal ou broadcast pour les threads éventuellement en attente.
non, non. Chaque thread fera sa boucle qui lui et propre. (en fait j'ai fait une boucle car l'implémentation pthread pour GCC sous Windows ne connait pas la fonction 'sem_post_multiple' bien pratique, elle existe au moins pour mac j'espère?).Citation:
je ne pense pas que ce soit bon parce que ce n'est pas fait d'une maniere transactionelle, plusieurs threads peuvent etre dans une loop et acquerir un peu du semaphore ... ce qui n'est pas bon a mon avis, il doivent acquerir l'ensemble des resources demandées sinon rien ... non ?
Un sémaphore, ce n'est dans le fond qu'une seule et unique variable entière. Ici la classe ne met a disposition que des fonctions pour manipuler cette variable.
Un mutex n'est au font qu'un booléan. Mais les instructions des processeurs permettent de manipuler ce boolean de façon concurrente d'un processus à l'autre.
Dans une implémentation de sémaphore, le mutex ne servirait que de barrière pour l'accès à la variable entière.
Et petite précision, dans l'éventualité d'une reprogrammation de la classe sémaphore, il vaudrait mieux utiliser un spin_mutex. La différence avec un mutex, c'est qu'il attend "sur place" une acquisition, car il ne restitue pas le processus au système. Ce qui coûterait beaucoup de temps face au peu de temps d'attente qu'un éventuel processus concurrent nécessite pour incrémenter le sémaphore.
bon a priori ca serait ca :
sauf que ca ne marche pas encore :aie:Code:
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
36
37
38
39
40 class semaphore { public: typedef semaphore self; typedef scoped_lock<self> scoped_lock; private: int count; condition_mutex mut; semaphore(const self &); const self &operator=(const self &); public: inline semaphore( ) { count = 1; } inline semaphore(int n) { count = n; } inline ~semaphore() {} inline void release() { mut.acquire(); count = count + 1; mut.signal(); mut.release(); } inline void release(int n) { for (int i=0; i<n; ++i) release(); } inline void acquire() { mut.acquire(); while(count == 0) mut.wait(); count = count - 1; mut.release(); } inline void acquire(int n) { for (int i=0; i<n; ++i) acquire(); } inline bool try_acquire() { condition_mutex::scoped_lock lock(mut); return count > 0; } inline int try_acquire(int n) { condition_mutex::scoped_lock lock(mut); return count > n ? n : count; } };
Le problème aussi, c'est qu'une implémentation perso a toute les chances d'être plus lente que l'implémentation d'une libraire système. Cette dernière fait probablement appel a des instructions spécifiques du processeur. Peut-être par exemple qu'il y a moyen d'utiliser des instructions atomiques pour incrémenter/décrémenter une valeur et donc sans recourir à un mutex.
tu as raison, on pourrait peut-etre quand meme faire l'implementation generique, puis se reposer sur Qt ou boost::thread pour une meilleure implementation (en tous les cas plus portable) que pthread non ?
par contre ce qui m'inquiete c'est que mon implementation ne marche toujours pas... tu aurais une idée ? la je ne vois vraiment pas...
EDIT: ca marche chez toi ?
Code:
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
36
37
38
39
40
41
42 class semaphore { public: typedef semaphore self; typedef scoped_lock<self> scoped_lock; private: int count; mutex mut; condition cond; semaphore(const self &); const self &operator=(const self &); public: inline semaphore( ) { count = 1; } inline semaphore(int n) { count = n; } inline ~semaphore() {} inline void release() { mut.acquire(); count = count + 1; cond.signal(); mut.release(); } inline void release(int n) { for (int i=0; i<n; ++i) release(); } inline void acquire() { mut.acquire(); assert(count >= 0); while(count == 0) cond.wait(mut); count = count - 1; mut.release(); } inline void acquire(int n) { for (int i=0; i<n; ++i) acquire(); } inline bool try_acquire() { mutex::scoped_lock lock(mut); return count > 0; } inline int try_acquire(int n) { mutex::scoped_lock lock(mut); return count > n ? n : count; } };
Non, non. J'ai toujours refusé les dépendances à des librairies extérieures.Citation:
Envoyé par epsilon68
Et en plus je n'aime pas du tout QT ni Boost.
Pour pthread c'est pas la même chose, c'est près à lemploi avec tout bon compilateur, et c'est (sensé) marcher d'un système à l'autre.
Comme ça je vois pas non plus.Citation:
Envoyé par epsilon68
Juste que le scoped_lock est plus pratique que d'utiliser le couple acquire/release, mais ça ne change rien dans le fond.
Vérifie que tu utilises bien le condition_mutex comme dans mon exemple
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 int x,y; typedef gmt::condition_mutex mutex_type; mutex_type cond; { mutex_type::scoped_lock lock(cond); while (x<=y) cond.wait(); // operate on x and y } { mutex_type::scoped_lock lock(cond); // modify x and y if (x>y) cond.signal(); }
je ne pense pas qu'il y ait d'erreur, j'ai maintenant peur que ca vienne de pthread :(
moi aussi...
mais je ne sais absolument plus d'ou ca peut venir...
...il est tard, je n'ai pas mangé, et je me leve tot demain :-(
a+
voila j'ai trouvé un lien ...
http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
mais c'est la meme implementation :aie:
ca y est je sais ce qui cloche avec
imaginons 2 threads qui se dispute 10 resources (semaphore) si chacun des threads en veut 8, he bien il y a blocage pur et simple parce que ils se seront alloués chacun 5 resources par exemple ....Code:void acquire(int n) { for (int i=0; i<n; ++i) acquire(); }
il vaudrait mieux faire acquerir n resources ou rien...
Qu'en penses-tu ?
Ton lien m'aurait été ben pratique lorsque j'ai programmé le multi-threading de ma bibliothèque.
Ta suggestion est probablement bonne, mais c'est pas là que ça cause une erreur d'exécution. A voir si c'est possible avec les interfaces de pthread et de Windows, pas sûr. De toute façon, cette fonction n'est appelée nulle part dans ma bibliothèque, et peut être radiée sans complexe.
J'avais pas remarqué hier soir, mais tes fonctions try_acquire ne font pas pas la même chose que les miennes. En fait ces fonctions doivent tout comme 'acquire' décrémenter le sémaphore, la différence c'est qu'elles n'attendent pas au cas où le sémaphore serait vide, et elles retournent la valeur dont le sémaphore a pu être immédiatement décrémenté.
Mais honnêtement je crois que je préfère une solution que se base sur les sémaphores de MacOS, quitte à utiliser un nom...
J'ai regardé quelques exemples sur internet, et c'est vraiment la galère ces sémaphores nommés.
C'est trop relou que 'sem_init' ne soit pas implémenté sous Mac...
J'ai vu encore un truc dans ton implémentation:
Tu initialises dans le constructeur le compteur avec 1, et non 0 comme moi.