2010-12-09 29 views
1

je thread-safety tester pour mieux comprendre ce qui est ce que je faisais:verrouillage de l'objet ne fonctionne pas pour la discussion de sécurité

J'ai un type appelé ThreadSample qui a deux méthodes et ce où le verrouillage se produit:

internal class ThreadTime 
    { 

     public void doSomething(string message) 
     { 
      lock (this) 
      { 
       DialogResult t = MessageBox.Show(message); 
       Thread.Sleep(2000); 
      } 
     } 

     public void anotherLife(string message) 
     { 
      MessageBox.Show("This is coming from anotherLife method and and current threadNumber is " + message); 
     } 
    } 

Fondamentalement, l'idée est quand doSomething() est appelée, elle doit verrouiller les objets entiers et d'autres threads peuvent même invoquer anotherLife méthode car ils attendent des autres threads pour libérer le verrou.

C'est la logique pour simuler le bouton de déblocage:

public partial class Form1 : Form 
{ 
    private ThreadTime time; 
    private Thread thread; 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     thread = new Thread(new ThreadStart(workerThread)); 
     time = new ThreadTime(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     thread.Start(); 
     //Thread.Sleep(1000); 
     time.anotherLife("Current thread is = " + "UI Thread"); 
    } 

    private void workerThread() 
    { 
     //time.doSomething("Current thread is = " + Thread.CurrentThread.ManagedThreadId); 
     time.doSomething("Worker Thread"); 
    } 
} 

Comme vous pouvez le voir dans le code ci-dessous à droite:

Lorsque Form est en cours d'initialisation, une nouvelle Thread et ThreadSample sont créés. Ensuite, lorsque l'utilisateur clique sur le button1, le thread est démarré et l'UIThread atteint et appelle anotherLife qui n'est pas sûr pour les threads au premier abord.

Quoi qu'il en soit, la sortie est:

  • Il y a deux MessageBox montré en même temps.

Ce que je me attendais est quand le nouveau thread appelle doSomething(), il obtient le verrou de l'objet et UIThread attend que le verrou soit relâché pour pouvoir invoquer la méthode anotherLife.

Quelqu'un peut-il expliquer pourquoi?

Merci.

+3

Pourquoi avez-vous la balise java quand il s'agit clairement de C#? Et pourquoi utilisez-vous les conventions de nommage Java en C#? –

+0

La façon dont j'ai lu votre question, il semble que vous avez une idée incorrecte sur le fonctionnement des verrous. Un verrou sur un objet n'est qu'un jeton à synchroniser. Rien n'arrive à l'objet de verrouillage lui-même. –

+0

Peut-être que le tag Java fait référence aux conventions plutôt qu'à la langue? –

Répondre

5

Ce que je me attendais est quand le nouveau thread appelle doSomething(), il obtient le verrou de l'objet et UIThread attend que le verrou soit relâché pour pouvoir invoquer la méthode anotherLife.

UIThread n'attendra pas qu'un verrou soit libéré avant de permettre anotherLife de procéder parce que anotherLife ne fonctionne pas une serrure. Les deux threads doivent exécuter une instruction lock (verrouillage sur le même objet) afin d'obtenir le comportement que vous recherchez. Essayez de modifier à quelque chose comme:

public void anotherLife(string message) 
{ 
    lock (this) 
    { 
     MessageBox.Show("This is coming from anotherLife method and and current threadNumber is " + message); 
    } 
} 
1

Eh bien, lock(this) ou lock(someThing) peut être un peu une métaphore trompeuse.

Il n'y a rien à faire 'to' this, mais plutôt l'argument à lock est utilisé comme un jeton. Tous les threads accédant à une ressource spécifique doivent utiliser le même jeton (objet) pour demander l'accès, sinon votre code est cassé.

C'est pourquoi souvent un objet d'aide est utilisé:

private List<string> myList = ...; 
private object myLock = new object(); 

lock(myLock) 
{ 
    myList.Add("foo"); 
} 

Ce système ne fonctionne que si tous les threads verrouillent myLock avant de changer myList.
Il est considéré comme une «meilleure pratique» car il n'est pas garanti qu'une liste <> peut être verrouillée en toute sécurité.

1

Seul votre fil observe le verrouillage

Vous devez changer

private void button1_Click(object sender, EventArgs e) 
    { 
     thread.Start(); 
     //Thread.Sleep(1000); 
     time.anotherLife("Current thread is = " + "UI Thread"); 
    } 

à

private void button1_Click(object sender, EventArgs e) 
    { 
     thread.Start(); 
     //Thread.Sleep(1000); 
lock(time) 
{ 
     time.anotherLife("Current thread is = " + "UI Thread"); 
} 
    } 

En fonction de votre code, il semble que vous pensez mettre un verrou sur un objet signifie que l'objet ne peut pas être accédé par autre chose. Ce n'est pas le cas. Un verrou sur un objet signifie simplement un autre verrou ne peut pas être placé sur l'objet tant que le premier verrou n'est pas relâché.

Vous accédez à l'objet à partir de deux endroits dans votre code, l'un dans le fil et l'autre dans l'événement bouton. Vous avez besoin d'un verrou dans les deux endroits.

+0

Ceci est une explication soignée. Surtout le dernier deuxième paragraphe. +1 merci. – Tarik