2015-03-08 1 views
0

Étant donné le scénario ci-dessous, la valeur de AValue dans DoSomething est-elle lue par le thread anonyme garanti "lisible"? c'est-à-dire, la valeur que j'attends? Pour moi, je ne pense pas que DoSomething soit hors de portée (ie, retourne) avant que le thread ne s'exécute réellement (ce qui peut être facilement vu en réalisant que la ligne x: = 2 s'exécute toujours avant que mon thread ne démarre - bien qu'avec les threads tous les paris sont désactivés et mon thread peut exécuter avant que DoSomething ne retourne). Je demande seulement parce que je n'ai jamais rencontré le scénario dans mes tests où AValue n'est pas égal à 1 (aka, la valeur transmise) donc je me demande si une référence implicite est tenue à la procédure et/ou thread (encore une fois peu probable car CreateAnonymousMethod crée simplement une instance d'un descendant TThread (TAnonymousThread) et appelle ma méthode anonyme "execute"). Je devine cependant que c'est la même chose car rien (dans ce scénario limité) n'a écrasé l'emplacement de la mémoire où AValue est stocké.Est-il sûr d'accéder à une variable locale dans le contexte d'un thread anonyme?

procedure TForm2.Button1Click(Sender: TObject); 
var 
    x: Integer; 
begin 
    x := 1; 
    DoSomething(x); 
    x := 2;// this line is only here for the purposes of placing a break point 
end; 

procedure TForm2.DoSomething(AValue: Integer); 
begin 

    TThread.CreateAnonymousThread(
    procedure 
    var 
     y: Integer; 
    begin 
     y := AValue; 

     if y = 1 then 
     MessageBox(0, 'Same', 'Value', MB_ICONINFORMATION or MB_OK) 
     else 
     MessageBox(0, 'Different', 'Value', MB_ICONINFORMATION or MB_OK) 
    end).Start; 
end; 

EDIT Juste pour vérifier, je voulais savoir s'il est sûr de capturer une variable locale dans le contexte d'un fil anonyme.

Répondre

2

Vous transmettez x par valeur. Cela signifie que la valeur de x est copiée lorsque vous appelez DoSomething(). Ainsi, chaque fois que le thread anonyme est exécuté, il n'a aucune référence à x. Le thread utilisait une variable capturée initialisée avec la valeur d'origine x. En d'autres termes, le thread anonyme ne peut pas voir si vous changez x plus tard dans l'événement ButtonClick1.


Remarque, si vous modifiez la AValue locale DoSomething() après que le fil anonyme est construit, cela affectera le résultat de votre fil.

procedure TForm2.DoSomething(AValue: Integer); 
begin 

    TThread.CreateAnonymousThread(
    procedure 
    var 
     y: Integer; 
    begin 
     y := AValue; 

     if y = 1 then 
     MessageBox(0, 'Same', 'Value', MB_ICONINFORMATION or MB_OK) 
     else 
     MessageBox(0, 'Different', 'Value', MB_ICONINFORMATION or MB_OK) 
    end).Start; 
    AValue := 3; // <-- This value will likely be seen by the anonymous thread. 
end; 

Si vous voulez éviter ce scénario, vous pouvez saisir la valeur AValue comme ceci:

procedure TForm4.DoSomething(AValue: Integer); 
    function CaptureValue(y: Integer) : TProc; 
    begin 
    Result := 
     procedure 
     begin 
     if y = 1 then 
     MessageBox(0, 'Same', 'Value', MB_ICONINFORMATION or MB_OK) 
     else 
     MessageBox(0, 'Different', 'Value', MB_ICONINFORMATION or MB_OK) 
    end; 
    end; 
var 
    p : TProc; 
begin 
    p := CaptureValue(AValue); 
    TThread.CreateAnonymousThread(p) 
    .Start; 
    AValue := 3; // <-- The anonymous method is unaffected by this change ! 
end; 

Le documentation explique que la AValue variable locale externe est capturée par référence par la méthode anonyme:

Si une méthode anonyme fait référence à une variable locale externe dans son corps, cette variable est "capturée". La capture signifie prolonger la durée de vie de la variable, de sorte qu'elle dure aussi longtemps que la valeur de la méthode anonyme, plutôt que de mourir avec sa routine de déclaration. Notez que la capture de variables capture des variables et non des valeurs. Si la valeur d'une variable change après avoir été capturée en construisant une méthode anonyme, la valeur de la variable capturée par la méthode anonyme change également, car il s'agit de la même variable avec le même stockage. Les variables capturées sont stockées sur le tas et non sur la pile.

+0

Oui, désolé. Je comprends complètement que x: = 2 ne sera pas reflété dans le fil anonyme. Ce que je veux savoir, c'est si (dans l'exemple ci-dessus - mais aussi dans des scénarios plus compliqués) que AValue est garanti à 1 lorsque le thread est exécuté. c'est à dire, "Thread Safe". – Jason

+0

Réponse mise à jour. Si vous modifiez AValue plus tard dans la méthode DoSomething, vous êtes en difficulté. –

+0

Oui. Comprendre.Donc je peux supposer que AValue sera toujours 1? c'est-à-dire que mon AnonymousThread peut accéder en toute sécurité aux variables locales? – Jason