OVH Cloud OVH Cloud

comment retourner une variable synchronisée

29 réponses
Avatar
pasde.hcyrano.spam
bonsoir,

j'ai un probleme vraiment bete

inline void POSIXThread::isInterrupted(bool& ret) {

mutex.lock();
ret = _interrupt;
mutex.unlock();

}

me parais vraiment "bouzin"

j'aimerai une signature du genre :

bool POSIXThread::isInterrupted();

comment puis faire, cela doit etre simple, mais je ne vois pas :-(

merci de votre aide

--
Bruno Causse
http://perso.wanadoo.fr/othello

10 réponses

1 2 3
Avatar
Arnaud Meurgues
Bruno Causse wrote:

inline void POSIXThread::isInterrupted(bool& ret) {

mutex.lock();
ret = _interrupt;
mutex.unlock();

}

j'aimerai une signature du genre :

bool POSIXThread::isInterrupted();

comment puis faire, cela doit etre simple, mais je ne vois pas :-(


Je ne suis pas certain de comprendre ce que vous voulez

bool POSIXThread::isInterrupted() {
bool result;

mutex.lock();
result = _interrupt;
mutex.unlock();

return result;
}

ne vous convient pas ?

--
Arnaud

Avatar
pasde.hcyrano.spam
Arnaud Meurgues wrote:

bool POSIXThread::isInterrupted() {
bool result;

mutex.lock();
result = _interrupt;
mutex.unlock();

return result;
}


result n'est pas detruit a la fin de la fonction?

--
Bruno Causse
http://perso.wanadoo.fr/othello

Avatar
pasde.hcyrano.spam
Bruno Causse wrote:

bool POSIXThread::isInterrupted() {
bool result;

mutex.lock();
result = _interrupt;
mutex.unlock();

return result;
}


result n'est pas detruit a la fin de la fonction?


ok, je viens de lire, return initialise une variable non nommée du type
renvoyé (= copie?)

la variable non nommée est non synchronisée et la valeur de _interrupt a
peu etre changé entre temps non?

vous le remarquez, je debute :-)
--
Bruno Causse
http://perso.wanadoo.fr/othello


Avatar
Sylvain
Bruno Causse wrote on 12/03/2006 00:11:
Arnaud Meurgues wrote:

bool POSIXThread::isInterrupted() {
bool result;

mutex.lock();
result = _interrupt;
mutex.unlock();

return result;
}


result n'est pas detruit a la fin de la fonction?



que signifirait "détruire" un type primitif bool ?

il n'existe pas de destructeur masqué pour les types de base - et
retourner une instance de classe non const, qui provoquerait une
destruction s'accompagnerait également d'une copie; dit autrement,
toutes les méthodes ne sont pas 'void' par contrainte.

ici l'état de "_interrupt" (que j'imagine défini comme une donnée membre
de votre classe et modifiée par d'autres méthodes sous contôle du mutex)
est retourné comme attendu.

Sylvain.


Avatar
pasde.hcyrano.spam
Bruno Causse wrote:

vous le remarquez, je debute :-)


desolé, je viens de "reflechir" aucun probleme. les problemes apres
minuit sont souvent du a la fatigue, je ne devrai pas me coucher aussi
tard :-);

merci quand meme.
bonne nuit


--
Bruno Causse
http://perso.wanadoo.fr/othello

Avatar
Sylvain
Bruno Causse wrote on 12/03/2006 00:21:
Bruno Causse wrote:

bool POSIXThread::isInterrupted() {
bool result;

mutex.lock();
result = _interrupt;
mutex.unlock();

return result;
}
result n'est pas detruit a la fin de la fonction?



ok, je viens de lire, return initialise une variable non nommée du type
renvoyé (= copie?)


"return" place ici sur la pile, la valeur courante de _interrupt et
redonne la main à l'appelant, celui-ci récupère donc la valeur.

(les subtilités propres aux conventions d'appel sont HS ici)

une "copie" -- au sens création d'un containeur et récopie de l'état
n'existera que pour une méthode retournant une référence non const.

la variable non nommée est non synchronisée et la valeur de _interrupt a
peu etre changé entre temps non?


entre quel *temps* ?

a) mutex.lock() est suspendu tant que le mutex est déjà locké (par une
autre méthode de cette instance exécutée apr un autre thread par exemple).
b) lors de l'affectation "result = _interrupt", vous stockez bien la
valeur courante de cette variable
c) mutex.unlock() libère l'élément synchronisé, donc tout autre bout de
code qui aurait invoqué "mutex.lock()" qlq part pourrait avoir repris la
main et changé la valeur de "_interrupt"; cela reste peut probable mais
peut subvenir, cela dépends avant tout de votre code (comment sont gérer
les threads applicatifs) et du système (comment switche-t-il entre
threads préemptifs).

dans la plupart des cas, vous devriez obtenir la valeur (toujours)
courante au moment où l'appelant poursuit son process, mais la validité
de cet état est imprévisible donc un code tel:

bool state = myThread.isInterrupted();
if (state){
fais de trucs avec
}

n'est pas safe si vous devez être sur que personne n'a repris le
contrôle sur myThread.

si vous êtes dans un tel cas, vous placerez le code utilisant the thread
dans un bloc lock() / unlock().

Sylvain.



Avatar
Patrick 'Zener' Brunet
Bonjour.

Je réponds à Bruno Causse
bonsoir,

j'ai un probleme vraiment bete

inline void POSIXThread::isInterrupted(bool& ret) {

mutex.lock();
ret = _interrupt;
mutex.unlock();

}

me parais vraiment "bouzin"

j'aimerai une signature du genre :

bool POSIXThread::isInterrupted();



Vous avez deux problèmes de principe, à part la grammaire :-)

1) En faisant une entorse raisonnable à la philosophie du "tout objet" pour
coller à la réalité de l'implémentation (ici en C++), c'est le coût de
l'invocation qui décide si on procède par passage de référence ou par copie:

void CTruc::Operation( CBigData & context)
{
...
context.SetValue( ...);
}

ou

bool CTruc::Operation( bool context_in)
{
bool context_out;
...
return( context_out);
}

2) Si le but est de réaliser une opération dans un contexte thread-safe en
utilisant un mutex, vous devez considérer que la période thread-safe est
délimitée par les API originelles d'acquisition et de restitution du mutex,
pas par les fonctions dans lesquelles vous les emballez.
Il y a de plus une éventualité de ne **pas** obtenir le mutex, ce qui
conduit à un deadlock si vous ne prévoyez pas d'échappatoire (retour en
erreur ou timeout).

Donc si vous voulez emballer ces deux opérations, il faut faire comme ça
(dans le principe):

bool CContext::GetMutex()
{
int ErrorCode;

// Depends on the mutex API
ErrorCode = mutex.Wait( TIMEOUT_DELAY);
// Demo code, actual test condition should be inverted: if( OK)
return( true);
if( ErrorCode == TIMEOUT || ErrorCode == ERROR_XXX)
return( false);
// Beginning of thread-safe area
return( true);
}

CContext::ReleaseMutex()
{
// End of thread-safe area
mutex.Release(); // No error expected, else should take care
}

...
if( CContext::GetMutex())
{
// Thread-safe only there -->
...
// --> End thread-safe
CContext::ReleaseMutex();
}
else
{
// Error recovery
}

Si vous voulez emballer complètement la récupération thread-safe d'un
résultat, ça conduit à un code dans le genre du vôtre initial, améliorable
selon 1), mais donc tenez compte aussi de l'éventualité de ne pas pourvoir
accéder au mutex, ce qui implique une valeur de retour spéciale pour votre
fonction IsInterrupted(), qui par ailleurs selon ces considérations, devrait
être rebaptisée.

Hope It Helps,
Cordially :o)

--
/***************************************
* Patrick BRUNET
* E-mail: lien sur http://zener131.free.fr/ContactMe
***************************************/

Avatar
kanze
Sylvain wrote:
Bruno Causse wrote on 12/03/2006 00:21:
Bruno Causse wrote:

bool POSIXThread::isInterrupted() {
bool result;

mutex.lock();
result = _interrupt;
mutex.unlock();

return result;
}
result n'est pas detruit a la fin de la fonction?



ok, je viens de lire, return initialise une variable non
nommée du type renvoyé (= copie?)


"return" place ici sur la pile, la valeur courante de
_interrupt et redonne la main à l'appelant, celui-ci récupère
donc la valeur.


Juste un détail, mais je ne connais pas de compilateur où une
valeur de retour de type bool ne se ferait pas par régistre.

(les subtilités propres aux conventions d'appel sont HS ici)

une "copie" -- au sens création d'un containeur et récopie de
l'état n'existera que pour une méthode retournant une
référence non const.


Il y a bien une « copie », au moins conceptuelle. Il y en a même
deux : une vers un « temporaire » dans la fonction appelée, et
une seconde du temporaire vers la destination finale au site
appelant. Mais le compilateur a pas mal de liberté pour
optimiser, y compris dans les cas des objets complexes, avec
constructeur de copie à effets de bords.

En fait, avec bool, c'est une copie d'une variable locale vers
un régistre. Et très souvent, l'appelant l'utilise directement
du régistre, sans plus.

la variable non nommée est non synchronisée et la valeur de
_interrupt a peu etre changé entre temps non?



Certainement. C'est le principe du multi-thread. Tel que tu l'a
écrit, la valeur du retour fait un « snapshot » du valeur
instantanée de la variable.

Si c'est important que la valeur de _interrupt ne change pas
pendant plus de temps, il faut prendre le lock à un niveau plus
haut. Mais sache qu'il s'agit toujours d'une prise de vue
«@instantanée ». Le thread qui modifie la variable a pû le
faire tout de suite avant que tu prends le lock, ou tout de
suite après que tu le libère ; il n'y a pas de déterminisme.

Vue les noms, j'imagine que tu « polles », c-à-d que tu appelles
la fonction périodiquement pour savoir si ton thread a été
interrompu. Alors... si la valeur de _interrupt change après que
tu l'as lue, tu verras la nouvelle valeur la prochaine fois que
tu polles. Le lock, ici, ne sert que pour garantir l'atomicité
de la mise à jour et la synchronisation de la mémoire.

entre quel *temps* ?


Entre le temps qu'il a lu la valeur, et le temps qu'il en
utilise la copie, non ?

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34




Avatar
kanze
Arnaud Meurgues wrote:
Bruno Causse wrote:

inline void POSIXThread::isInterrupted(bool& ret) {

mutex.lock();
ret = _interrupt;
mutex.unlock();
}

j'aimerai une signature du genre :

bool POSIXThread::isInterrupted();

comment puis faire, cela doit etre simple, mais je ne vois pas :-(


Je ne suis pas certain de comprendre ce que vous voulez

bool POSIXThread::isInterrupted() {
bool result;


A remettre plus tard.

mutex.lock();
result = _interrupt;


bool result = _interrupt ;

Pas la peine de declarer la variable avant de pouvoir
l'initialiser.

mutex.unlock();

return result;
}

ne vous convient pas ?


Probablement, mais il me semble qu'une solution avec un
scoped_lock serait encore préférable :

bool
POSIXThread::isInterrupted()
{
scoped_lock l( mutex ) ;
return _interrupt ;
}

Pas la peine de declarer la variable -- le compilateur copierait
la valeur de retour quelque part avant d'appeler le destructeur
de scoped_lock (qui lui libèrera le lock que le constructeur a
pris).

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Arnaud Meurgues
kanze wrote:


bool
POSIXThread::isInterrupted()
{
scoped_lock l( mutex ) ;
return _interrupt ;
}

Pas la peine de declarer la variable -- le compilateur copierait
la valeur de retour quelque part avant d'appeler le destructeur
de scoped_lock (qui lui libèrera le lock que le constructeur a
pris).


Oui. Je n'étais pas certain du bon comportement d'une telle construction
et j'ai eu la flemme de regarder dans la norme.

--
Arnaud

1 2 3