Perl/Tk et les threads

Le
genomart
Bonjour,

Je souhaite comprendre le fonctionnement de Perl Tk et les threads
afin de faire un petit article pour résumer leurs utilisations.
Le but des threads si j'ai bien compris, est de pouvoir lancer une
procédure (fonction perl) dans un autre processus indépendant du
script principal et d'ailleurs, Perl ne crée pas vraiment un autre
processus mais bon c'est comme ci.
Pour cela, on utilise le module "threads". Son utilisation est simple,
mais c'est lorsqu'on veut s'amuser à faire du Perl/Tk que les ennuis
commencent.

Pour tester threads et Tk, j'ai fait deux scripts qui ont pour but de
lister les fichiers d'un répertoire choisi par l'utilisateur. Pendant
le listing sur la console DOS, la fenêtre principale doit rester
normale (ne pas être figée) et afficher l'heure (toutes les secondes).

En parcourant internet, j'ai trouvé des posts disant que les threads
doivent être déclaré au tout début du script, et que la procédure
lancée en background ne doit pas faire appelle à du Tk, je n'ai pas
compris l'explication!!!!

En faite, si je crée un thread dans un callback de bouton, je n'ai pas
de message d'erreur. Par contre si j'essaye de détacher le thread, de
faire un join ou autre, j'ai un message de type Free to wrong pool
1897d98 not 235e08.

Pour être plus clair, voici mes 2 scripts :
Le premier est => PasPropreThreadTk.pl
J'y lance des threads directement dans le callback du bouton. Ça
fonctionne bien, mais il parait que ce n'est pas propre, une idée? A
quel type de problème dois je me préparer?
$thr->detach; ne pose aucun souci, par contre si j'avais écris
$thr = threads->create( &ListerFichiersRecursif, $RepertoireLister )-
>detach;
j'aurais eu un message Free to wrong , qu'est ce que ça veut dire?
est ce que mes threads sont vraiment détachés quand je fais $thr-
>detach; via cette méthode?
Voici le script
==

#!/usr/bin/perl
use threads;
use threads::shared;
use warnings;
use strict;
use Tk;
use utf8;
use Time::HiRes qw( sleep );

my $thr;
my $Id;


my $fenetre = new MainWindow(
-title => "threads Tk ",
-background => "white",
);
$fenetre->minsize( 300, 300 );
my $MessageAccueil = "Perl/Tk et les threads";

# Affichage d'un texte
my $LabelAccueil = $fenetre->Label(
-text => $MessageAccueil,
-background => "white",
)->pack();

my $date;
$fenetre->Label(
-textvariable => $date,
-background => "white",
)->pack( -side => "bottom" );

# Affichage d'un bouton pour fermer la fenêtre
$fenetre->Button(
-text => "Fermez la fenêtre",
-command => &Quitter,
)->pack( -side => "left", );

my $BoutonLister = $fenetre->Button( -text => "Lister fichier ", )-
>pack( -side => "right", );
$BoutonLister->configure(
-command => sub {
my $RepertoireLister = SelectOneDirectory( $fenetre, "choix
repertoire" );
$BoutonLister->configure( -state => "disabled" );
$thr = threads->create( &ListerFichiersRecursif,
$RepertoireLister );
$thr->detach;

$Id = $fenetre->repeat(1000, [&VerifThread, $thr,
$BoutonLister]);
},
);

$fenetre->repeat( 1000, sub { my @tab_date = localtime(time); $date =
"$tab_date[2]:$tab_date[1]:$tab_date[0]"; } );

MainLoop();

sub VerifThread {
my ($thr, $BoutonLister) = @_;
unless ( $thr->is_running() ) {
$BoutonLister->configure( -state => "normal" );
$Id->cancel;
}
return;
}

sub Quitter {
if ( $thr and $thr->is_running() ) {
print "Thread is running, please wait ";
return;
}

threads->exit(0);
exit;
return;
}

sub ListerFichiersRecursif {
my ($repertoire) = @_;

opendir( REP, $repertoire )
or die "impossible d'ouvrir le repertoire $repertoire";
my @file_rep = grep { !/^..?$/ } readdir(REP);
closedir(REP);
my @fichiers = ();

foreach my $nom (@file_rep) {
if ( -f "$repertoire/$nom" ) {
push( @fichiers, "$repertoire/$nom" );
print "$repertoire/$nom";
}
elsif ( -d "$repertoire/$nom" ) {
push( @fichiers, &ListerFichiersRecursif("$repertoire/$nom") );
}
}
return @fichiers;
}

sub SelectOneDirectory {
my ( $Widget, $Title ) = @_;
my $Directory = $Widget->chooseDirectory(
-title => $Title,
-initialdir => $ENV{DefaultDirectory},
-mustexist => 1,
);

if ( defined $Directory and -e $Directory ) {
$Directory =~ s{\}{/}g;
$ENV{DefaultDirectory} = $Directory;

return $Directory;
}

return;
}

==


Le deuxième est => PropreThreadTk.pl
Je crée un thread au début du script et ensuite, je le laisse vraiment
s'exécuter en jonglant avec des variables partagées.Ça fonctionne
bien, mais je trouve que c'est prise de tête dans la conception car on
est obligé de savoir la procédure à lancer dès le début du script=
.
Mais bon, j'attends vos avis pour m'éclairer sur le sujet! de plus on
ne peut pas partager des variables faisant référence à une subroutine
anonyme, sinon ça aurait été l'idéale.

Voici le script :
==

#!/usr/bin/perl
use threads;
use threads::shared;

use warnings;
use strict;
use Tk;
use utf8;
use Time::HiRes qw( sleep );
use Data::Dumper;


my ( $thread );
my %HashProcedure :shared;

$HashProcedure{InWork} = 0;
$thread = threads->create( &LancerProcedure );
$HashProcedure{TID} = $thread->tid();
$HashProcedure{Argument} = undef;
my $IDRepeat = 0;


my $fenetre = new MainWindow(
-title => "threads Tk ",
-background => "white",
);
$fenetre->minsize( 300, 300 );
my $MessageAccueil = "Perl/Tk et les threads";

# Affichage d'un texte
my $LabelAccueil = $fenetre->Label(
-text => $MessageAccueil,
-background => "white",
)->pack();

my $date ;
$fenetre->Label(
-textvariable => $date,
-background => "white",
)->pack( -side => "bottom" );

# Affichage d'un bouton pour fermer la fenêtre
$fenetre->Button(
-text => "Fermez la fenêtre",
-command => &Quitter,
)->pack( -side => "left", );
my $Id;

my $BoutonLister
= $fenetre->Button( -text => "Lister fichier ", )->pack( -side =>
"right", );
$BoutonLister->configure(
-command => sub {
$BoutonLister->configure( -state => "disabled" );
$HashProcedure{Argument} = SelectOneDirectory( $fenetre,
"Sélectionner un répertoire" );
$HashProcedure{InWork} = 1;
$IDRepeat = $fenetre->repeat(1000, [&VerifListage, $fenetre,
$BoutonLister]);
},
);

$fenetre->repeat( 1000, sub { my @tab_date = localtime(time); $date =
"$tab_date[2]:$tab_date[1]:$tab_date[0]"; } );

MainLoop();

sub Quitter {
$thread->detach();
exit;
}

sub LancerProcedure {

while (1) {


if ( $HashProcedure{InWork} == 1 ) {
ListerFichiersRecursif($HashProcedure{Argument});
$HashProcedure{InWork} = 0;
}
else {
sleep 1;
}
}
return;
}

sub VerifListage {
my ( $Widget, $Bouton ) = @_;
if ( $HashProcedure{InWork} == 0 ) {
$Bouton->configure( -state => "active" );
$Widget->afterCancel( $IDRepeat );
}

return;
}

sub ListerFichiersRecursif {
my ($repertoire) = @_;

opendir( REP, $repertoire )
or die "impossible d'ouvrir le repertoire $repertoire";
my @file_rep = grep { !/^..?$/ } readdir(REP);
closedir(REP);
my @fichiers = ();

foreach my $nom (@file_rep) {
if ( -f "$repertoire/$nom" ) {
push( @fichiers, "$repertoire/$nom" );
print "$repertoire/$nom";
}
elsif ( -d "$repertoire/$nom" ) {
push( @fichiers, &ListerFichiersRecursif("$repertoire/$nom") );
}
}
return @fichiers;
}

sub SelectOneDirectory {
my ( $Widget, $Title ) = @_;
my $Directory = $Widget->chooseDirectory(
-title => $Title,
-initialdir => $ENV{DefaultDirectory},
-mustexist => 1,
);

if ( defined $Directory and -e $Directory ) {
$Directory =~ s{\}{/}g;
$ENV{DefaultDirectory} = $Directory;

return $Directory;
}

return;
}
==


Voilà, vous pouvez les tester. J'attends vos réponses pour m'éclairer
sur ce sujet.

NB : Sinon, lorsque j'ai besoin de lancer des exe depuis mes scripts
Perl TK, j'utilise le module Win32::Process et la ça fonctionne à
merveille car l'exe est bien lancé dans un processus indépendant et on
peut jouer par la suite avec le numéro du pid.
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Paul Gaborit
Le #18597401
À (at) Thu, 5 Feb 2009 16:41:09 -0800 (PST),
écrivait (wrote):
Pour être plus clair, voici mes 2 scripts :
Le premier est ====> PasPropreThreadTk.pl
J'y lance des threads directement dans le callback du bouton. Ça
fonctionne bien, mais il parait que ce n'est pas propre, une idée? A
quel type de problème dois je me préparer?



La version 804 de Perl/Tk n'est pas 'thread safe'. Petit extrait de

- Big projects
Make Perl/Tk thread-safe.

C'est donc bien dans la partie 'ToDo' ! Par contre, je ne saurais pas
vous dire précisément où se situe le(s) éventuel(s) problème(s).

$thr->detach; ne pose aucun souci, par contre si j'avais écris
$thr = threads->create( &ListerFichiersRecursif,
$RepertoireLister)->detach; j'aurais eu un message Free to wrong
..., qu'est ce que ça veut dire?



Tout simplement que le résultat de la méthode 'detach' n'est pas un
thread contrairement à celui de 'create' ! ;-)

Je crée un thread au début du script et ensuite, je le laisse vraiment
s'exécuter en jonglant avec des variables partagées.Ça fonctionne
bien, mais je trouve que c'est prise de tête dans la conception car on
est obligé de savoir la procédure à lancer dès le début du script.
Mais bon, j'attends vos avis pour m'éclairer sur le sujet! de plus on
ne peut pas partager des variables faisant référence à une subroutine
anonyme, sinon ça aurait été l'idéale.



Je pense que c'est la solution la plus propre. En fait, il faut un
thread principal qui ne sert qu'à communiquer avec le thread qui gère
l'interface Tk et à créer, si besoin, de nouveaux threads. Un peu
comme un chef d'orchestre.

Je ne comprends pas votre remarque ou votre besoin concernant les
références à de subroutines anonymes...

--
Paul Gaborit - Perl en français -
genomart
Le #18598561
Merci pour votre réponse Paul.

Que veut dire "thread safe" concrétement ?

En ce qui concerne les références à mes soubroutines, je m'explique.

Pour le moment, la façon la plus propre de créer des threads en Tk est
d'en créer u par exemple en début de script, avant tout code Tk.
Donc, je me suis dit que je pourrais en créer un par exemple. Ensuite
créer un hash partagé.

use threads;
use threads::shared;
my %HashProcedure :shared;
my $thread = threads->create( &LancerProcedure );

Par la suite, dans ce hash, je souhaiterais y stocker ces valeurs :
$HashProcedure{InWork} = 0; # Permet de dire à mon thread de faire
quelque chose ou non
$HashProcedure{TID} = $thread->tid(); # tid du thread

Jusqu'ici pas de souci.
Si je souhaite stocker l'objet de mon thread dans le hash partagé, ça
ne fonctionne pas, ex :
$HashProcedure{Monthread} = $thread; => message d'erreur :
Invalid value for shared scalar at . C'est donc le premier souci.

Supposons que dans le script on a 1 procédure simple :
sub PrintBonjour {
my ( $Prenom ) = @_;
print "Bonjour $Prenomn";
}

Si je souhaite la stocker dans mon hash de la sorte :
$HashProcedure{Fonction} = &PrintBonjour;

J'ai le même message d'erreur Invalid value for shared scalar at ...

C'est dommage, car cela m'aurait permis Dans mes codes Callback des
boutons Tk de passer des procédures à souhait avec différents
arguments si possible.
De plus en ne changeant que l'adresse de la procédure dans
$HashProcedure{Fonction} via $HashProcedure{Fonction} =
&MaProcedurequelconque;

Est ce vraiment impossible de faire ce genre de partage?

Merci!
Paul Gaborit
Le #18602521
À (at) Fri, 6 Feb 2009 03:42:33 -0800 (PST),
écrivait (wrote):
Merci pour votre réponse Paul.

Que veut dire "thread safe" concrétement ?



safe = sûr, sans danger, sans risque.

Donc Perl/Tk avec des threads n'est pas sûr, n'est pas sans danger,
n'est pas sans risque... Et c'est l'auteur du code qui le dit, je
pense donc qu'on peut lui faire confiance. ;-)

En ce qui concerne les références à mes soubroutines, je m'explique.

Pour le moment, la façon la plus propre de créer des threads en Tk est
d'en créer u par exemple en début de script, avant tout code Tk.
Donc, je me suis dit que je pourrais en créer un par exemple. Ensuite
créer un hash partagé.

use threads;
use threads::shared;
my %HashProcedure :shared;
my $thread = threads->create( &LancerProcedure );

Par la suite, dans ce hash, je souhaiterais y stocker ces valeurs :
$HashProcedure{InWork} = 0; # Permet de dire à mon thread de faire
quelque chose ou non
$HashProcedure{TID} = $thread->tid(); # tid du thread

Jusqu'ici pas de souci.
Si je souhaite stocker l'objet de mon thread dans le hash partagé, ça
ne fonctionne pas, ex :
$HashProcedure{Monthread} = $thread; => message d'erreur :
Invalid value for shared scalar at . C'est donc le premier souci.

Supposons que dans le script on a 1 procédure simple :
sub PrintBonjour {
my ( $Prenom ) = @_;
print "Bonjour $Prenomn";
}

Si je souhaite la stocker dans mon hash de la sorte :
$HashProcedure{Fonction} = &PrintBonjour;

J'ai le même message d'erreur Invalid value for shared scalar at ...



Ça, ce ne sont pas des problèmes liés à Perk/Tk. Ce sont les
limitations du partage de données entre threads en Perl.

La doc de 'threads::shared' est assez claire (dans la section "bugs
and limitations") :

When "share" is used on arrays, hashes, array refs or hash refs,
any data they contain will be lost. [...] Therefore, populate such
variables after declaring them as shared. (Scalar and scalar refs
are not affected by this problem.)

It is often not wise to share an object unless the class itself has
been written to support sharing.

Une traduction vite fait sur le gaz :

L'appel de 'share' sur des tableaux, tables de hachages ou sur des
références vers ces types de structures videra ces structures. Cela
signifie qu'il ne faut remplir ces structures qu'après leur
déclaration en tant que structure partagée.

Il est quasiment impossible de partager un objet si la classe à
laquelle il appartient n'a été conçue pour.

Une référence vers une subroutine ne fait pas partie du type de
valeurs partgeables. Si on y réfléchit bien, cette impossibilité est
logique puisque rien ne garantit que la subroutine existe ou soit la
même dans les autres threads.

C'est dommage, car cela m'aurait permis Dans mes codes Callback des


boutons Tk de passer des procédures à souhait avec différents
arguments si possible.



Pour cela, il vaut mieux passer par des appels explicites.

De plus en ne changeant que l'adresse de la procédure dans
$HashProcedure{Fonction} via $HashProcedure{Fonction} > &MaProcedurequelconque;

Est ce vraiment impossible de faire ce genre de partage?



Tel que décrit, c'est impossible. Mais rien n'empêche de mettre au
point une structure de données qui amènent les mêmes résultats. En
utilisant par exemple une table de hachage intermédiaire de références
vers les fonctions.

# toutes les fonctions appelables...

my %fonctions = (
MaProcedurequelconque => &MaProcedurequelconque,
PrintBonjour => &PrintBonjour;
);

# hachage partagée pour choisir la fonction à appeler

$HashProcedure{Fonction} = PrintBonjour;

# appel de la bonne fonction dans un autyre thread

$fonction{$HashProcedure{Fonction}}->(...);

--
Paul Gaborit - Perl en français -
mpg
Le #18604961
Paul Gaborit scripsit:

Donc Perl/Tk avec des threads n'est pas sûr, n'est pas sans danger,
n'est pas sans risque... Et c'est l'auteur du code qui le dit, je
pense donc qu'on peut lui faire confiance. ;-)



Certes, mais pour les incultes, peux-tu détailler quels sont les types
de risques spécifiquement associés à l'utilisation de threads ? (Parce
que si on veut pousser le bouchon, aucun code n'est sans risque...)

--
Manuel Pégourié-Gonnard Institut de mathématiques de Jussieu
http://weblog.elzevir.fr/ http://people.math.jussieu.fr/~mpg/
Paul Gaborit
Le #18605471
À (at) Sat, 7 Feb 2009 00:11:22 +0100 (CET),
mpg
Paul Gaborit scripsit:

Donc Perl/Tk avec des threads n'est pas sûr, n'est pas sans danger,
n'est pas sans risque... Et c'est l'auteur du code qui le dit, je
pense donc qu'on peut lui faire confiance. ;-)



Certes, mais pour les incultes, peux-tu détailler quels sont les types
de risques spécifiquement associés à l'utilisation de threads ? (Parce
que si on veut pousser le bouchon, aucun code n'est sans risque...)



Ben tous les problèmes classiques de parallèlisme : appels multiples à
du code qui n'a pas été prévu pour, modifications incohérente des
données...

En Perl/Tk, par exemple, on peut attacher une variable à un widget
afin qu'il en affiche sa valeur : c'est complètement transparent pour
le programmeur : une affectation à la variable et l'interface
suit... Que se passe-t-il si c'est un autre thread qui modifie cette
variable ? Comment savoir quel thread doit modifier l'interface ? Et
comment a-t-il accès aux variables internes de l'interface Tk
puisqu'elles ne sont pas partagées et surtout pas gérées par Perl
puisque c'est une bibliothèque externe.

Mais encore une fois, je n'ai pas d'exemples précis en Perl/Tk puisque
les fois où j'avais besoin de gérer de longues tâches, j'ai utilisé
soit du véritable multi-processus soit une barre d'avancement avec un
bouton d'annulation et le reste de l'interface momentanément
désactivée... Et je fais confiance à l'auteur pour ne pas avoir besoin
de chercher un exemple où Perl/Tk en multi-thread risque de planter.

Si on tient absolument à faire du multi-thread, le seul moyen consiste
à isoler toute la partie Tk dans un thread unique (comme on le fait
dnas du multi-processus) et à gérer soi-même les échanges entre les
différents threads et l'interface Tk.

--
Paul Gaborit - Perl en français -
genomart
Le #18623521
On 6 fév, 16:18, Paul Gaborit
À (at) Fri, 6 Feb 2009 03:42:33 -0800 (PST),
écrivait (wrote):

> Merci pour votre réponse Paul.

> Que veut dire "thread safe" concrétement ?

safe = sûr, sans danger, sans risque.

Donc Perl/Tk avec des threads n'est pas sûr, n'est pas sans danger,
n'est pas sans risque... Et c'est l'auteur du code qui le dit, je
pense donc qu'on peut lui faire confiance. ;-)



> En ce qui concerne les références à mes soubroutines, je m'expliq ue.

> Pour le moment, la façon la plus propre de créer des threads en Tk est
> d'en créer u par exemple en début de script, avant tout code Tk.
> Donc, je me suis dit que je pourrais en créer un par exemple. Ensuite
> créer un hash partagé.

> use threads;
> use threads::shared;
> my %HashProcedure :shared;
> my $thread = threads->create( &LancerProcedure );

> Par la suite, dans ce hash, je souhaiterais y stocker ces valeurs :
> $HashProcedure{InWork}    = 0;  # Permet de dire à mon thread de faire
> quelque chose ou non
> $HashProcedure{TID}       = $thread->tid(); # tid du thread

> Jusqu'ici pas de souci.
> Si je souhaite stocker l'objet de mon thread dans le hash partagé, ça
> ne fonctionne pas, ex :
> $HashProcedure{Monthread} = $thread; => message d'erreur :
> Invalid value for shared scalar at . C'est donc le premier souci.

> Supposons que dans le script on a 1 procédure simple :
> sub PrintBonjour {
>   my ( $Prenom ) = @_;
>   print "Bonjour $Prenomn";
> }

> Si je souhaite la stocker dans mon hash de la sorte :
> $HashProcedure{Fonction} = &PrintBonjour;

> J'ai le même message d'erreur Invalid value for shared scalar at ...

Ça, ce ne sont pas des problèmes liés à Perk/Tk. Ce sont les
limitations du partage de données entre threads en Perl.

La doc de 'threads::shared' est assez claire (dans la section "bugs
and limitations") :

   When "share" is used on arrays, hashes, array refs or hash refs,
   any data they contain will be lost. [...] Therefore, populate such
   variables after declaring them as shared.  (Scalar and scalar re fs
   are not affected by this problem.)

   It is often not wise to share an object unless the class itself ha s
   been written to support sharing.

Une traduction vite fait sur le gaz :

   L'appel de 'share' sur des tableaux, tables de hachages ou sur des
   références vers ces types de structures videra ces structures. Cela
   signifie qu'il ne faut remplir ces structures qu'après leur
   déclaration en tant que structure partagée.

   Il est quasiment impossible de partager un objet si la classe à
   laquelle il appartient n'a été conçue pour.

Une référence vers une subroutine ne fait pas partie du type de
valeurs partgeables. Si on y réfléchit bien, cette impossibilité es t
logique puisque rien ne garantit que la subroutine existe ou soit la
même dans les autres threads.

>> C'est dommage, car cela m'aurait permis Dans mes codes Callback des
> boutons Tk de passer des procédures à souhait avec différents
> arguments si possible.

Pour cela, il vaut mieux passer par des appels explicites.

> De plus en ne changeant que l'adresse de la procédure dans
> $HashProcedure{Fonction} via $HashProcedure{Fonction} =
> &MaProcedurequelconque;

> Est ce vraiment impossible de faire ce genre de partage?

Tel que décrit, c'est impossible. Mais rien n'empêche de mettre au
point une structure de données qui amènent les mêmes résultats. E n
utilisant par exemple une table de hachage intermédiaire de référen ces
vers les fonctions.

# toutes les fonctions appelables...

my %fonctions = (
   MaProcedurequelconque => &MaProcedurequelconque,
   PrintBonjour => &PrintBonjour;
);

# hachage partagée pour choisir la fonction à appeler

$HashProcedure{Fonction} = PrintBonjour;

# appel de la bonne fonction dans un autyre thread

$fonction{$HashProcedure{Fonction}}->(...);

--
Paul Gaborit - Perl en français -


Merci pour vos réponses. C'est vrai que dans la doc CPAN, il est
spécifié qu'on ne peut absolument pas partagé des structures
complexes.
Pour revenir à votre exemple sur la création d'un hash intermédiaire
contenant la liste des procédure à appeler, on revient au même
problème :-)
sauf si j'ail oupé quelque chose :

my %fonctions = (
MaProcedurequelconque => &MaProcedurequelconque,
PrintBonjour => &PrintBonjour;
);

# hachage partagée pour choisir la fonction à appeler

$HashProcedure{Fonction} = PrintBonjour;

jusqu'ici pas de soucis, mais à l'appel du hash %fonctions dans un
autre thread, on aura 2 problèmes :
1) Vu qu'il n'a pas été partagé, il sera impossible d'y accéder dan s
un autre thread.
2) Si on essaye de le partager, on aura les même refus car les clés
pointent vers une soubroutine, donc on revient au même problème. :-)

fonctions{$HashProcedure{Fonction}}->(...);
Paul Gaborit
Le #18634071
À (at) Mon, 9 Feb 2009 02:20:48 -0800 (PST),
écrivait (wrote):
Merci pour vos réponses. C'est vrai que dans la doc CPAN, il est
spécifié qu'on ne peut absolument pas partagé des structures
complexes.



On peut... mais il faut partager explicitement tous les composants
élémentaires. Ce qui est éventuellement faisable si on maîtrise toute
la structure.

Pour revenir à votre exemple sur la création d'un hash intermédiaire
contenant la liste des procédure à appeler, on revient au même
problème :-)
sauf si j'ail oupé quelque chose :

my %fonctions = (
MaProcedurequelconque => &MaProcedurequelconque,
PrintBonjour => &PrintBonjour;
);

# hachage partagée pour choisir la fonction à appeler

$HashProcedure{Fonction} = PrintBonjour;

jusqu'ici pas de soucis, mais à l'appel du hash %fonctions dans un
autre thread, on aura 2 problèmes :
1) Vu qu'il n'a pas été partagé, il sera impossible d'y accéder dans
un autre thread.



Les threads ont accès à toutes les données et à tout le code. Inutile
de partager la table de hachage %fonctions. À la rigeur, ça peut très
bien être une constante.

La seule valeur partagée (au sens synchronisée entre les différents
threads), c'est le nom de la clé choisie dans la table %fonctions.

fonctions{$HashProcedure{Fonction}}->(...);





--
Paul Gaborit - Perl en français -
genomart
Le #18641081
On 10 fév, 14:12, Paul Gaborit
À (at) Mon, 9 Feb 2009 02:20:48 -0800 (PST),
écrivait (wrote):

> Merci pour vos réponses. C'est vrai que dans la doc CPAN, il est
> spécifié qu'on ne peut absolument pas partagé des structures
> complexes.

On peut... mais il faut partager explicitement tous les composants
élémentaires. Ce qui est éventuellement faisable si on maîtrise t oute
la structure.



> Pour revenir à votre exemple sur la création d'un hash intermédia ire
> contenant la liste des procédure à appeler, on revient au même
> problème :-)
> sauf si j'ail oupé quelque chose :

> my %fonctions = (
>    MaProcedurequelconque => &MaProcedurequelconque,
>    PrintBonjour => &PrintBonjour;
> );

> # hachage partagée pour choisir la fonction à appeler

> $HashProcedure{Fonction} = PrintBonjour;

> jusqu'ici pas de soucis, mais à l'appel du hash %fonctions dans un
> autre thread, on aura 2 problèmes :
> 1) Vu qu'il n'a pas été partagé, il sera impossible d'y accéder dans
> un autre thread.

Les threads ont accès à toutes les données et à tout le code. Inu tile
de partager la table de hachage %fonctions. À la rigeur, ça peut tr ès
bien être une constante.

La seule valeur partagée (au sens synchronisée entre les différents
threads), c'est le nom de la clé choisie dans la table %fonctions.

> fonctions{$HashProcedure{Fonction}}->(...);

--
Paul Gaborit - Perl en français -


Merci Paul.
Maintenant, je sais comment manipuler correctement les threads en TK.
J'ai des astuces en tête.
Je te remercie.
Publicité
Poster une réponse
Anonyme