2010-11-17 5 views
2

J'ai une classe qui exécute du code transactionnel.
laisse supposer:Partage de la transaction de partage entre threads

class Worker 
{ 
    public void doWork() 
    { 
     //I do not want to create a new transaction. Instead, i want to use the environmenttransaction used by the caller of this method 
     using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))    { 
      workItem1(); 
      workItem2(); 
      workItem3(); 
      scope.Complete(); 
     } 
    } 

Maintenant, j'ai quelques fils qui exécutent ce code:

Worker worker = new Worker(); 
using (TransactionScope transaction = new TransactionScope()) 
{ 
    Thread Thread1 = new Thread(new ThreadStart(worker.doWork)); 
    Thread1.Start(); 
    Thread Thread2 = new Thread(new ThreadStart(worker.doWork)); 
    Thread2.Start(); 
    Thread Thread3 = new Thread(new ThreadStart(worker.doWork)); 
    Thread3.Start(); 

    Thread.Sleep(10000); //this should be enough to all the workers finish their job 

    transaction.Complete(); 
} 

Chaque thread crée une propre transaction. Comment puis-je partager la même transaction entre tous les threads?

+0

Je suis assez sûr que c'est une mauvaise idée à faire. En fonction de vos tâches, cela pourrait aussi être impossible. –

Répondre

1

Le code que vous avez créera une condition de concurrence. Vous appelez presque immédiatement scope.complete avant la fin de vos discussions.

Cependant, même si chaque collaborateur crée une étendue de transaction, celle-ci est en fait imbriquée par .Net dans la portée de transaction de niveau supérieur, si une nouvelle est créée.

Si vous souhaitez avoir une transaction multicouche imbriquée, vous pouvez créer la nouvelle étendue avec ScopeOption.RequiresNew. Mais ceci est la réponse à une vraie question, c'est pourquoi vous voudriez faire ceci. Les transactions signifient intrinsèquement que votre travail est en quelque sorte séquentiel ou critique pour se produire dans un certain ordre. Si vous pouvez effectuer le parallélisme du travail, essayez de le faire dans des transactions séparées, dans la mesure du possible, limitez la portée au temps le plus court possible pour empêcher les verrouillages, etc.

+1

Salut. Je ne veux pas d'option RequiresNew. En fait, c'est exactement ce que je ne veux pas. Je veux juste que tous les «travailleurs» participent à la même transaction. J'ai mis quelques commentaires sur mon code. –

+0

Eh bien, n'est-ce pas une nouvelle portée dans votre thread? Il détectera toujours qu'une transaction valide est en cours d'exécution lorsque le thread démarre. – Spence

+0

ET même si vous mettez une nouvelle portée dans la méthode, ils seront toujours imbriqués dans la transaction de niveau supérieur. RequiresNew est utile si vous avez des transactions COM et que vous voulez qu'elles apparaissent séparément sur MSTSC. – Spence

-3

Le problème avec votre code est que vous n'êtes pas attendant tous les fils pour terminer leur travail avant d'appeler:

  transaction.Complete(); 

donc, l'un de vos fils peut appeler cette méthode avant votre transaction multithread complète comme un atomique. Vous devrez probablement utiliser la classe Semaphore pour éviter la collision.

Aussi, je voudrais examiner en utilisant PLinq si votre environnement le permet.

6

Vous pouvez jeter un oeil à la classe DependentTransaction qui est utile pour la transaction entre plusieurs threads. Voir le documentation pour cela.

+0

En suivant le lien - "Cette documentation est archivée et n'est pas conservée." en tant que FYI – Mark

+0

Le lien pointe maintenant vers l'endroit correct. – Kit

Questions connexes