J'ai un petit problème avec gcc et (il me semble) les opérations
atomiques,
1/ considérons un processus père qui lance des tas de processus de
calculs à l'aide de fork().
2/ un fils donné est averti de la disponibilité d'une donnée par un
signal (SIGQUIT ici) qui est déclanché par un kill() depuis le père.
3/ le gestionnaire du SIGQUIT est initialisé par un sigaction() dans
le fils avec l'option NODEFER (il peut y avoir plusieurs interruptions
simultanées à traiter en même temps).
Questions :
1/ le problème se situe-t-il au niveau du gestionnaire de signal
(interruption6) ou de l'utilisation de la variable globale ?
2/ Si le problème se situe au niveau de
var_globale_nombre_objets_injectes++, opération qui est non atomique
(si j'ai bien compris), comment la rendre atomique (et portable) ?
3/ le compilo est gcc. Est-il assez intelligent pour optimiser
l'utilisation de la variable tampon ?
J'ai un petit problème avec gcc et (il me semble) les opérations
atomiques,
1/ considérons un processus père qui lance des tas de processus de
calculs à l'aide de fork().
2/ un fils donné est averti de la disponibilité d'une donnée par un
signal (SIGQUIT ici) qui est déclanché par un kill() depuis le père.
3/ le gestionnaire du SIGQUIT est initialisé par un sigaction() dans
le fils avec l'option NODEFER (il peut y avoir plusieurs interruptions
simultanées à traiter en même temps).
Questions :
1/ le problème se situe-t-il au niveau du gestionnaire de signal
(interruption6) ou de l'utilisation de la variable globale ?
2/ Si le problème se situe au niveau de
var_globale_nombre_objets_injectes++, opération qui est non atomique
(si j'ai bien compris), comment la rendre atomique (et portable) ?
3/ le compilo est gcc. Est-il assez intelligent pour optimiser
l'utilisation de la variable tampon ?
J'ai un petit problème avec gcc et (il me semble) les opérations
atomiques,
1/ considérons un processus père qui lance des tas de processus de
calculs à l'aide de fork().
2/ un fils donné est averti de la disponibilité d'une donnée par un
signal (SIGQUIT ici) qui est déclanché par un kill() depuis le père.
3/ le gestionnaire du SIGQUIT est initialisé par un sigaction() dans
le fils avec l'option NODEFER (il peut y avoir plusieurs interruptions
simultanées à traiter en même temps).
Questions :
1/ le problème se situe-t-il au niveau du gestionnaire de signal
(interruption6) ou de l'utilisation de la variable globale ?
2/ Si le problème se situe au niveau de
var_globale_nombre_objets_injectes++, opération qui est non atomique
(si j'ai bien compris), comment la rendre atomique (et portable) ?
3/ le compilo est gcc. Est-il assez intelligent pour optimiser
l'utilisation de la variable tampon ?
4/ il y a un thread de surveillance qui tourne dans le fils, donc
j'ai collé un mutex dans le traitement de l'interruption histoire
d'être sûr de ne pas accéder en même temps à la même variable.
4/ il y a un thread de surveillance qui tourne dans le fils, donc
j'ai collé un mutex dans le traitement de l'interruption histoire
d'être sûr de ne pas accéder en même temps à la même variable.
4/ il y a un thread de surveillance qui tourne dans le fils, donc
j'ai collé un mutex dans le traitement de l'interruption histoire
d'être sûr de ne pas accéder en même temps à la même variable.
En news:, JKB va escriure:J'ai un petit problème avec gcc et (il me semble) les opérations
atomiques,
Quelle version ?
GCC est renommé pour avoir un comportement plus ou moins ératique à ce
niveau (souvent appellé « variable volatiles »), ce qui génère des plaintes,
et en conséquence les développeurs de GCC ont pas mal louvoyé.
1/ considérons un processus père qui lance des tas de processus de
calculs à l'aide de fork().
Mmmm, peut-être qu'en postant sur fcou, non ?
Moi j'en étais resté sur le fait que beaucoup de fils + signal = problèmes
avec le modèle de synchronisation de Unix. Donc ÀMHA la question risque de
déborder passablement le cadre de ce groupe.2/ un fils donné est averti de la disponibilité d'une donnée par un
signal (SIGQUIT ici) qui est déclanché par un kill() depuis le père.
Et deux SIGQUIT envoyés groupés _avant_ que le fils ne se réveille,
qu'est-ce que cela donne ?
3/ le gestionnaire du SIGQUIT est initialisé par un sigaction() dans
le fils avec l'option NODEFER (il peut y avoir plusieurs interruptions
simultanées à traiter en même temps).
Donc tu contournes en utilisant une construction encore moins portable,
requerrant Posix-2001... J'espère que tu es conscient :
1. qu'il ne faut pas dédaigner de possible bogues au niveau de
l'implémentation par le système utilisé ;
2. que la question est passablement hors sujet ici.
Questions :
1/ le problème se situe-t-il au niveau du gestionnaire de signal
(interruption6) ou de l'utilisation de la variable globale ?
Pour le savoir, tu découpes le problème en deux, en remplaçant l'un puis
l'autre des bouts de code et le reste inchangé.
Une manière simple de commencer serait d'écrire en assembleur l'opération
sur la variable globale (ce qui va probablement priver le compilateur
d'opporrtunité pour faire des choses incorrectes, ou qui va te montrer tout
de suite qu'il y a un souci s'il y a un problème d'aliasing ce qui est
probable).
Une autre manière de faire est d'essayer un autre compilateur...2/ Si le problème se situe au niveau de
var_globale_nombre_objets_injectes++, opération qui est non atomique
(si j'ai bien compris), comment la rendre atomique (et portable) ?
man pthread3/ le compilo est gcc. Est-il assez intelligent pour optimiser
l'utilisation de la variable tampon ?
Je ne sais pas si GCC est intelligent.
Mais je crois que ses concepteurs sont suffisament <xxx> pour essayer de le
lui faire faire des optimisations de cet acabit...
En news:slrngfgqq7.gq7.knatschke@rayleigh.systella.fr, JKB va escriure:
J'ai un petit problème avec gcc et (il me semble) les opérations
atomiques,
Quelle version ?
GCC est renommé pour avoir un comportement plus ou moins ératique à ce
niveau (souvent appellé « variable volatiles »), ce qui génère des plaintes,
et en conséquence les développeurs de GCC ont pas mal louvoyé.
1/ considérons un processus père qui lance des tas de processus de
calculs à l'aide de fork().
Mmmm, peut-être qu'en postant sur fcou, non ?
Moi j'en étais resté sur le fait que beaucoup de fils + signal = problèmes
avec le modèle de synchronisation de Unix. Donc ÀMHA la question risque de
déborder passablement le cadre de ce groupe.
2/ un fils donné est averti de la disponibilité d'une donnée par un
signal (SIGQUIT ici) qui est déclanché par un kill() depuis le père.
Et deux SIGQUIT envoyés groupés _avant_ que le fils ne se réveille,
qu'est-ce que cela donne ?
3/ le gestionnaire du SIGQUIT est initialisé par un sigaction() dans
le fils avec l'option NODEFER (il peut y avoir plusieurs interruptions
simultanées à traiter en même temps).
Donc tu contournes en utilisant une construction encore moins portable,
requerrant Posix-2001... J'espère que tu es conscient :
1. qu'il ne faut pas dédaigner de possible bogues au niveau de
l'implémentation par le système utilisé ;
2. que la question est passablement hors sujet ici.
Questions :
1/ le problème se situe-t-il au niveau du gestionnaire de signal
(interruption6) ou de l'utilisation de la variable globale ?
Pour le savoir, tu découpes le problème en deux, en remplaçant l'un puis
l'autre des bouts de code et le reste inchangé.
Une manière simple de commencer serait d'écrire en assembleur l'opération
sur la variable globale (ce qui va probablement priver le compilateur
d'opporrtunité pour faire des choses incorrectes, ou qui va te montrer tout
de suite qu'il y a un souci s'il y a un problème d'aliasing ce qui est
probable).
Une autre manière de faire est d'essayer un autre compilateur...
2/ Si le problème se situe au niveau de
var_globale_nombre_objets_injectes++, opération qui est non atomique
(si j'ai bien compris), comment la rendre atomique (et portable) ?
man pthread
3/ le compilo est gcc. Est-il assez intelligent pour optimiser
l'utilisation de la variable tampon ?
Je ne sais pas si GCC est intelligent.
Mais je crois que ses concepteurs sont suffisament <xxx> pour essayer de le
lui faire faire des optimisations de cet acabit...
En news:, JKB va escriure:J'ai un petit problème avec gcc et (il me semble) les opérations
atomiques,
Quelle version ?
GCC est renommé pour avoir un comportement plus ou moins ératique à ce
niveau (souvent appellé « variable volatiles »), ce qui génère des plaintes,
et en conséquence les développeurs de GCC ont pas mal louvoyé.
1/ considérons un processus père qui lance des tas de processus de
calculs à l'aide de fork().
Mmmm, peut-être qu'en postant sur fcou, non ?
Moi j'en étais resté sur le fait que beaucoup de fils + signal = problèmes
avec le modèle de synchronisation de Unix. Donc ÀMHA la question risque de
déborder passablement le cadre de ce groupe.2/ un fils donné est averti de la disponibilité d'une donnée par un
signal (SIGQUIT ici) qui est déclanché par un kill() depuis le père.
Et deux SIGQUIT envoyés groupés _avant_ que le fils ne se réveille,
qu'est-ce que cela donne ?
3/ le gestionnaire du SIGQUIT est initialisé par un sigaction() dans
le fils avec l'option NODEFER (il peut y avoir plusieurs interruptions
simultanées à traiter en même temps).
Donc tu contournes en utilisant une construction encore moins portable,
requerrant Posix-2001... J'espère que tu es conscient :
1. qu'il ne faut pas dédaigner de possible bogues au niveau de
l'implémentation par le système utilisé ;
2. que la question est passablement hors sujet ici.
Questions :
1/ le problème se situe-t-il au niveau du gestionnaire de signal
(interruption6) ou de l'utilisation de la variable globale ?
Pour le savoir, tu découpes le problème en deux, en remplaçant l'un puis
l'autre des bouts de code et le reste inchangé.
Une manière simple de commencer serait d'écrire en assembleur l'opération
sur la variable globale (ce qui va probablement priver le compilateur
d'opporrtunité pour faire des choses incorrectes, ou qui va te montrer tout
de suite qu'il y a un souci s'il y a un problème d'aliasing ce qui est
probable).
Une autre manière de faire est d'essayer un autre compilateur...2/ Si le problème se situe au niveau de
var_globale_nombre_objets_injectes++, opération qui est non atomique
(si j'ai bien compris), comment la rendre atomique (et portable) ?
man pthread3/ le compilo est gcc. Est-il assez intelligent pour optimiser
l'utilisation de la variable tampon ?
Je ne sais pas si GCC est intelligent.
Mais je crois que ses concepteurs sont suffisament <xxx> pour essayer de le
lui faire faire des optimisations de cet acabit...
JKB writes:4/ il y a un thread de surveillance qui tourne dans le fils, donc
j'ai collé un mutex dans le traitement de l'interruption histoire
d'être sûr de ne pas accéder en même temps à la même variable.
Je comprends bien? Tu utilises un mutex dans un gestionnaire de signal?
Il ne me semble pas que ce sont des fonctions "async safe" (ce qui est
plus exigent que thread safe).
JKB <knatschke@koenigsberg.fr> writes:
4/ il y a un thread de surveillance qui tourne dans le fils, donc
j'ai collé un mutex dans le traitement de l'interruption histoire
d'être sûr de ne pas accéder en même temps à la même variable.
Je comprends bien? Tu utilises un mutex dans un gestionnaire de signal?
Il ne me semble pas que ce sont des fonctions "async safe" (ce qui est
plus exigent que thread safe).
JKB writes:4/ il y a un thread de surveillance qui tourne dans le fils, donc
j'ai collé un mutex dans le traitement de l'interruption histoire
d'être sûr de ne pas accéder en même temps à la même variable.
Je comprends bien? Tu utilises un mutex dans un gestionnaire de signal?
Il ne me semble pas que ce sont des fonctions "async safe" (ce qui est
plus exigent que thread safe).
On Fri, 17 Oct 2008 10:39:06 +0000 (UTC)
JKB [JKB] wrote:
JKB> Bonjour à tous,
JKB>
JKB> J'ai un petit problème avec gcc et (il me semble) les opérations
JKB> atomiques, mais je n'en suis vraiment pas sûr... Je m'explique :
JKB>
JKB> 1/ considérons un processus père qui lance des tas de processus de
JKB> calculs à l'aide de fork(). Chaque fils peut recevoir du père un
JKB> certain nombre de données par un pipe.
JKB> 2/ un fils donné est averti de la disponibilité d'une donnée par un
JKB> signal (SIGQUIT ici) qui est déclanché par un kill() depuis le père.
JKB> 3/ le gestionnaire du SIGQUIT est initialisé par un sigaction() dans
JKB> le fils avec l'option NODEFER (il peut y avoir plusieurs interruptions
JKB> simultanées à traiter en même temps).
JKB> 4/ il y a un thread de surveillance qui tourne dans le fils, donc
JKB> j'ai collé un mutex dans le traitement de l'interruption histoire
JKB> d'être sûr de ne pas accéder en même temps à la même variable.
petite question: pourquoi ne pas simplement utiliser select() pour savoir
quand il y a des choses a processer et traiter ce que read() nous donne ?
On Fri, 17 Oct 2008 10:39:06 +0000 (UTC)
JKB [JKB] wrote:
JKB> Bonjour à tous,
JKB>
JKB> J'ai un petit problème avec gcc et (il me semble) les opérations
JKB> atomiques, mais je n'en suis vraiment pas sûr... Je m'explique :
JKB>
JKB> 1/ considérons un processus père qui lance des tas de processus de
JKB> calculs à l'aide de fork(). Chaque fils peut recevoir du père un
JKB> certain nombre de données par un pipe.
JKB> 2/ un fils donné est averti de la disponibilité d'une donnée par un
JKB> signal (SIGQUIT ici) qui est déclanché par un kill() depuis le père.
JKB> 3/ le gestionnaire du SIGQUIT est initialisé par un sigaction() dans
JKB> le fils avec l'option NODEFER (il peut y avoir plusieurs interruptions
JKB> simultanées à traiter en même temps).
JKB> 4/ il y a un thread de surveillance qui tourne dans le fils, donc
JKB> j'ai collé un mutex dans le traitement de l'interruption histoire
JKB> d'être sûr de ne pas accéder en même temps à la même variable.
petite question: pourquoi ne pas simplement utiliser select() pour savoir
quand il y a des choses a processer et traiter ce que read() nous donne ?
On Fri, 17 Oct 2008 10:39:06 +0000 (UTC)
JKB [JKB] wrote:
JKB> Bonjour à tous,
JKB>
JKB> J'ai un petit problème avec gcc et (il me semble) les opérations
JKB> atomiques, mais je n'en suis vraiment pas sûr... Je m'explique :
JKB>
JKB> 1/ considérons un processus père qui lance des tas de processus de
JKB> calculs à l'aide de fork(). Chaque fils peut recevoir du père un
JKB> certain nombre de données par un pipe.
JKB> 2/ un fils donné est averti de la disponibilité d'une donnée par un
JKB> signal (SIGQUIT ici) qui est déclanché par un kill() depuis le père.
JKB> 3/ le gestionnaire du SIGQUIT est initialisé par un sigaction() dans
JKB> le fils avec l'option NODEFER (il peut y avoir plusieurs interruptions
JKB> simultanées à traiter en même temps).
JKB> 4/ il y a un thread de surveillance qui tourne dans le fils, donc
JKB> j'ai collé un mutex dans le traitement de l'interruption histoire
JKB> d'être sûr de ne pas accéder en même temps à la même variable.
petite question: pourquoi ne pas simplement utiliser select() pour savoir
quand il y a des choses a processer et traiter ce que read() nous donne ?
petite question: pourquoi ne pas simplement utiliser select() pour savoir
quand il y a des choses a processer et traiter ce que read() nous donne ?
J'avais dans un premier temps pensé à utiliser pselect(), mais cela
ne convient pas. Le fils a besoin de connaître le nombre de données
envoyées _avant_ de les lire, d'autant que certaines de ces données
sont utilisées groupées. L'utilisation de pselect() permet de savoir
qu'il y a au moins une donnée dans le pipe, mais pas d'en connaître le
nombre. Par ailleurs, comme le fils peut lire cette donnée longtemps
après l'appel pselect(), cela ne fonctionnera pas car il faudrait
lire chaque donnée _juste_ après le retour de pselect().
petite question: pourquoi ne pas simplement utiliser select() pour savoir
quand il y a des choses a processer et traiter ce que read() nous donne ?
J'avais dans un premier temps pensé à utiliser pselect(), mais cela
ne convient pas. Le fils a besoin de connaître le nombre de données
envoyées _avant_ de les lire, d'autant que certaines de ces données
sont utilisées groupées. L'utilisation de pselect() permet de savoir
qu'il y a au moins une donnée dans le pipe, mais pas d'en connaître le
nombre. Par ailleurs, comme le fils peut lire cette donnée longtemps
après l'appel pselect(), cela ne fonctionnera pas car il faudrait
lire chaque donnée _juste_ après le retour de pselect().
petite question: pourquoi ne pas simplement utiliser select() pour savoir
quand il y a des choses a processer et traiter ce que read() nous donne ?
J'avais dans un premier temps pensé à utiliser pselect(), mais cela
ne convient pas. Le fils a besoin de connaître le nombre de données
envoyées _avant_ de les lire, d'autant que certaines de ces données
sont utilisées groupées. L'utilisation de pselect() permet de savoir
qu'il y a au moins une donnée dans le pipe, mais pas d'en connaître le
nombre. Par ailleurs, comme le fils peut lire cette donnée longtemps
après l'appel pselect(), cela ne fonctionnera pas car il faudrait
lire chaque donnée _juste_ après le retour de pselect().
JKB:petite question: pourquoi ne pas simplement utiliser select() pour savoir
quand il y a des choses a processer et traiter ce que read() nous donne ?
J'avais dans un premier temps pensé à utiliser pselect(), mais cela
ne convient pas. Le fils a besoin de connaître le nombre de données
envoyées _avant_ de les lire, d'autant que certaines de ces données
sont utilisées groupées. L'utilisation de pselect() permet de savoir
qu'il y a au moins une donnée dans le pipe, mais pas d'en connaître le
nombre. Par ailleurs, comme le fils peut lire cette donnée longtemps
après l'appel pselect(), cela ne fonctionnera pas car il faudrait
lire chaque donnée _juste_ après le retour de pselect().
Dans ce cas tu peux utiliser le truc du "self-pipe" dans ton
gestionnaire de signal. Tu ajoutes dans un pipe un caractère à chaque
signal reçu.
Tu ne précises pas une chose importante : c'est dans quel contexte de
thread est appelé ton gestionnaire, et si le mutex est récursif.
D'après
ce que j'ai lu la méthode canonique est de bloquer tous les signaux
dans le thread qui travaille et d'avoir un autre thread qui ne gère
que les signaux.
JKB:
petite question: pourquoi ne pas simplement utiliser select() pour savoir
quand il y a des choses a processer et traiter ce que read() nous donne ?
J'avais dans un premier temps pensé à utiliser pselect(), mais cela
ne convient pas. Le fils a besoin de connaître le nombre de données
envoyées _avant_ de les lire, d'autant que certaines de ces données
sont utilisées groupées. L'utilisation de pselect() permet de savoir
qu'il y a au moins une donnée dans le pipe, mais pas d'en connaître le
nombre. Par ailleurs, comme le fils peut lire cette donnée longtemps
après l'appel pselect(), cela ne fonctionnera pas car il faudrait
lire chaque donnée _juste_ après le retour de pselect().
Dans ce cas tu peux utiliser le truc du "self-pipe" dans ton
gestionnaire de signal. Tu ajoutes dans un pipe un caractère à chaque
signal reçu.
Tu ne précises pas une chose importante : c'est dans quel contexte de
thread est appelé ton gestionnaire, et si le mutex est récursif.
D'après
ce que j'ai lu la méthode canonique est de bloquer tous les signaux
dans le thread qui travaille et d'avoir un autre thread qui ne gère
que les signaux.
JKB:petite question: pourquoi ne pas simplement utiliser select() pour savoir
quand il y a des choses a processer et traiter ce que read() nous donne ?
J'avais dans un premier temps pensé à utiliser pselect(), mais cela
ne convient pas. Le fils a besoin de connaître le nombre de données
envoyées _avant_ de les lire, d'autant que certaines de ces données
sont utilisées groupées. L'utilisation de pselect() permet de savoir
qu'il y a au moins une donnée dans le pipe, mais pas d'en connaître le
nombre. Par ailleurs, comme le fils peut lire cette donnée longtemps
après l'appel pselect(), cela ne fonctionnera pas car il faudrait
lire chaque donnée _juste_ après le retour de pselect().
Dans ce cas tu peux utiliser le truc du "self-pipe" dans ton
gestionnaire de signal. Tu ajoutes dans un pipe un caractère à chaque
signal reçu.
Tu ne précises pas une chose importante : c'est dans quel contexte de
thread est appelé ton gestionnaire, et si le mutex est récursif.
D'après
ce que j'ai lu la méthode canonique est de bloquer tous les signaux
dans le thread qui travaille et d'avoir un autre thread qui ne gère
que les signaux.
Bonjour à tous,
J'ai un petit problème avec gcc et (il me semble) les opérations
atomiques, mais je n'en suis vraiment pas sûr... Je m'explique :
1/ considérons un processus père qui lance des tas de processus de
calculs à l'aide de fork(). Chaque fils peut recevoir du père un
certain nombre de données par un pipe.
2/ un fils donné est averti de la disponibilité d'une donnée par un
signal (SIGQUIT ici) qui est déclanché par un kill() depuis le père.
3/ le gestionnaire du SIGQUIT est initialisé par un sigaction() dans
le fils avec l'option NODEFER (il peut y avoir plusieurs interruptions
simultanées à traiter en même temps).
4/ il y a un thread de surveillance qui tourne dans le fils, donc
j'ai collé un mutex dans le traitement de l'interruption histoire
d'être sûr de ne pas accéder en même temps à la même variable.
pthread_mutex_t exclusion = PTHREAD_MUTEX_INITIALIZER; // Var globale
void
interruption6(int signal)
{
if (var_globale_debug_signaux != 0)
{
printf("[%d] SIGINJECT/SIGQUITn", (int) getpid());
fflush(stdout);
}
pthread_mutex_lock(&exclusion);
var_globale_nombre_objets_injectes++; // ce truc est un sig_atomic_t
pthread_mutex_unlock(&exclusion);
return;
}
Chaque fois que le père désire envoyer une donnée à l'un de ses
fils, il commence par envoyé le signal SIGQUIT au fils en question.
Cette étape se passe bien (kill() ne renvoie aucune erreur).
Le fils utilise la variable var_globale_nombre_objets_injectes comme
suit :
int tampon;
int nombre_variables_disponibles;
pthread_mutex_lock(&exclusion);
tampon = var_globale_nombre_objets_injectes;
if (tampon != 0)
{
var_globale_nombre_objets_injectes -= tampon;
nombre_variables_disponibles += tampon;
}
pthread_mutex_lock(&exclusion);
Lorsque nombre_variables_disponibles est positif, le fils peut lire
une donnée.
Problème : au bout d'un certain temps (en environnement parallèle),
le fils rate une donnée. En fait, la donnée a bien été envoyée dans
le pipe, mais var_globale_nombre_objets_injectes n'a pas été
incrémentée par le SIGQUIT (alors que la sortie console me prouve
que le SIGQUIT a été traité). Le programme s'arrête donc et il
suffit de signaler le fils (par un kill -SIGQUIT pid) pour le
relancer.
Questions :
1/ le problème se situe-t-il au niveau du gestionnaire de signal
(interruption6) ou de l'utilisation de la variable globale ?
2/ Si le problème se situe au niveau de
var_globale_nombre_objets_injectes++, opération qui est non atomique
(si j'ai bien compris), comment la rendre atomique (et portable) ?
3/ le compilo est gcc. Est-il assez intelligent pour optimiser
l'utilisation de la variable tampon ? J'ai essayé de faire un calcul
sur celle-ci histoire d'essyer de forcer gcc à ne pas la supprimer
sans succès...
Merci de vos lumières,
JKB
Bonjour à tous,
J'ai un petit problème avec gcc et (il me semble) les opérations
atomiques, mais je n'en suis vraiment pas sûr... Je m'explique :
1/ considérons un processus père qui lance des tas de processus de
calculs à l'aide de fork(). Chaque fils peut recevoir du père un
certain nombre de données par un pipe.
2/ un fils donné est averti de la disponibilité d'une donnée par un
signal (SIGQUIT ici) qui est déclanché par un kill() depuis le père.
3/ le gestionnaire du SIGQUIT est initialisé par un sigaction() dans
le fils avec l'option NODEFER (il peut y avoir plusieurs interruptions
simultanées à traiter en même temps).
4/ il y a un thread de surveillance qui tourne dans le fils, donc
j'ai collé un mutex dans le traitement de l'interruption histoire
d'être sûr de ne pas accéder en même temps à la même variable.
pthread_mutex_t exclusion = PTHREAD_MUTEX_INITIALIZER; // Var globale
void
interruption6(int signal)
{
if (var_globale_debug_signaux != 0)
{
printf("[%d] SIGINJECT/SIGQUITn", (int) getpid());
fflush(stdout);
}
pthread_mutex_lock(&exclusion);
var_globale_nombre_objets_injectes++; // ce truc est un sig_atomic_t
pthread_mutex_unlock(&exclusion);
return;
}
Chaque fois que le père désire envoyer une donnée à l'un de ses
fils, il commence par envoyé le signal SIGQUIT au fils en question.
Cette étape se passe bien (kill() ne renvoie aucune erreur).
Le fils utilise la variable var_globale_nombre_objets_injectes comme
suit :
int tampon;
int nombre_variables_disponibles;
pthread_mutex_lock(&exclusion);
tampon = var_globale_nombre_objets_injectes;
if (tampon != 0)
{
var_globale_nombre_objets_injectes -= tampon;
nombre_variables_disponibles += tampon;
}
pthread_mutex_lock(&exclusion);
Lorsque nombre_variables_disponibles est positif, le fils peut lire
une donnée.
Problème : au bout d'un certain temps (en environnement parallèle),
le fils rate une donnée. En fait, la donnée a bien été envoyée dans
le pipe, mais var_globale_nombre_objets_injectes n'a pas été
incrémentée par le SIGQUIT (alors que la sortie console me prouve
que le SIGQUIT a été traité). Le programme s'arrête donc et il
suffit de signaler le fils (par un kill -SIGQUIT pid) pour le
relancer.
Questions :
1/ le problème se situe-t-il au niveau du gestionnaire de signal
(interruption6) ou de l'utilisation de la variable globale ?
2/ Si le problème se situe au niveau de
var_globale_nombre_objets_injectes++, opération qui est non atomique
(si j'ai bien compris), comment la rendre atomique (et portable) ?
3/ le compilo est gcc. Est-il assez intelligent pour optimiser
l'utilisation de la variable tampon ? J'ai essayé de faire un calcul
sur celle-ci histoire d'essyer de forcer gcc à ne pas la supprimer
sans succès...
Merci de vos lumières,
JKB
Bonjour à tous,
J'ai un petit problème avec gcc et (il me semble) les opérations
atomiques, mais je n'en suis vraiment pas sûr... Je m'explique :
1/ considérons un processus père qui lance des tas de processus de
calculs à l'aide de fork(). Chaque fils peut recevoir du père un
certain nombre de données par un pipe.
2/ un fils donné est averti de la disponibilité d'une donnée par un
signal (SIGQUIT ici) qui est déclanché par un kill() depuis le père.
3/ le gestionnaire du SIGQUIT est initialisé par un sigaction() dans
le fils avec l'option NODEFER (il peut y avoir plusieurs interruptions
simultanées à traiter en même temps).
4/ il y a un thread de surveillance qui tourne dans le fils, donc
j'ai collé un mutex dans le traitement de l'interruption histoire
d'être sûr de ne pas accéder en même temps à la même variable.
pthread_mutex_t exclusion = PTHREAD_MUTEX_INITIALIZER; // Var globale
void
interruption6(int signal)
{
if (var_globale_debug_signaux != 0)
{
printf("[%d] SIGINJECT/SIGQUITn", (int) getpid());
fflush(stdout);
}
pthread_mutex_lock(&exclusion);
var_globale_nombre_objets_injectes++; // ce truc est un sig_atomic_t
pthread_mutex_unlock(&exclusion);
return;
}
Chaque fois que le père désire envoyer une donnée à l'un de ses
fils, il commence par envoyé le signal SIGQUIT au fils en question.
Cette étape se passe bien (kill() ne renvoie aucune erreur).
Le fils utilise la variable var_globale_nombre_objets_injectes comme
suit :
int tampon;
int nombre_variables_disponibles;
pthread_mutex_lock(&exclusion);
tampon = var_globale_nombre_objets_injectes;
if (tampon != 0)
{
var_globale_nombre_objets_injectes -= tampon;
nombre_variables_disponibles += tampon;
}
pthread_mutex_lock(&exclusion);
Lorsque nombre_variables_disponibles est positif, le fils peut lire
une donnée.
Problème : au bout d'un certain temps (en environnement parallèle),
le fils rate une donnée. En fait, la donnée a bien été envoyée dans
le pipe, mais var_globale_nombre_objets_injectes n'a pas été
incrémentée par le SIGQUIT (alors que la sortie console me prouve
que le SIGQUIT a été traité). Le programme s'arrête donc et il
suffit de signaler le fils (par un kill -SIGQUIT pid) pour le
relancer.
Questions :
1/ le problème se situe-t-il au niveau du gestionnaire de signal
(interruption6) ou de l'utilisation de la variable globale ?
2/ Si le problème se situe au niveau de
var_globale_nombre_objets_injectes++, opération qui est non atomique
(si j'ai bien compris), comment la rendre atomique (et portable) ?
3/ le compilo est gcc. Est-il assez intelligent pour optimiser
l'utilisation de la variable tampon ? J'ai essayé de faire un calcul
sur celle-ci histoire d'essyer de forcer gcc à ne pas la supprimer
sans succès...
Merci de vos lumières,
JKB
Je ne vais pas polémiquer sur l'architecture de ta solution, cela a été
suffisamment fait.
En ce qui concerne les variables "atomiques", il y a des opérations
atomiques associés.
En utilisant des signaux non temps-réel, tu peux en perdre. Au passage
pourquoi ne pas avoir pris les signaux SIGUSR1 ou SIGUSR2 ?
Dans ton cas tu ne peux empiler que deux signaux : celui que tu traites
et celui en attente de traitement. Si un troisième signal arrive, tu
perds un cycle. Puisque des signaux temps-réel sont disponibles
utilise-les !
Maintenant si tu as des données de taille variable à transmettre tu peux
utiliser des sockets unix et passer des messages avec une entete
rensiegnant la taille.
++
Je ne vais pas polémiquer sur l'architecture de ta solution, cela a été
suffisamment fait.
En ce qui concerne les variables "atomiques", il y a des opérations
atomiques associés.
En utilisant des signaux non temps-réel, tu peux en perdre. Au passage
pourquoi ne pas avoir pris les signaux SIGUSR1 ou SIGUSR2 ?
Dans ton cas tu ne peux empiler que deux signaux : celui que tu traites
et celui en attente de traitement. Si un troisième signal arrive, tu
perds un cycle. Puisque des signaux temps-réel sont disponibles
utilise-les !
Maintenant si tu as des données de taille variable à transmettre tu peux
utiliser des sockets unix et passer des messages avec une entete
rensiegnant la taille.
++
Je ne vais pas polémiquer sur l'architecture de ta solution, cela a été
suffisamment fait.
En ce qui concerne les variables "atomiques", il y a des opérations
atomiques associés.
En utilisant des signaux non temps-réel, tu peux en perdre. Au passage
pourquoi ne pas avoir pris les signaux SIGUSR1 ou SIGUSR2 ?
Dans ton cas tu ne peux empiler que deux signaux : celui que tu traites
et celui en attente de traitement. Si un troisième signal arrive, tu
perds un cycle. Puisque des signaux temps-réel sont disponibles
utilise-les !
Maintenant si tu as des données de taille variable à transmettre tu peux
utiliser des sockets unix et passer des messages avec une entete
rensiegnant la taille.
++