Dela via


Hantera samtidighet med DependentTransaction

Objektet Transaction skapas med hjälp av DependentClone metoden . Det enda syftet är att garantera att transaktionen inte kan genomföras medan vissa andra kodstycken (till exempel en arbetstråd) fortfarande utför arbete med transaktionen. När det arbete som utförs inom den klonade transaktionen är klart och redo att genomföras kan det meddela den som skapat transaktionen med hjälp Complete av metoden. Därför kan du bevara datas konsekvens och korrekthet.

Klassen DependentTransaction kan också användas för att hantera samtidighet mellan asynkrona uppgifter. I det här scenariot kan överordnad fortsätta att köra valfri kod medan den beroende klonen fungerar på sina egna uppgifter. Med andra ord blockeras inte den överordnade körningen förrän den beroende har slutförts.

Skapa en beroende klon

Om du vill skapa en beroende transaktion anropar du DependentClone metoden och skickar DependentCloneOption uppräkningen som en parameter. Den här parametern definierar beteendet för transaktionen om Commit anropas på den överordnade transaktionen innan den beroende klonen anger att den är redo för transaktionen att checka in (genom att anropa Complete metoden). Följande värden är giltiga för den här parametern:

  • BlockCommitUntilComplete skapar en beroende transaktion som blockerar incheckningsprocessen för den överordnade transaktionen tills den överordnade transaktionen överskrider tidsgränsen, eller tills Complete den anropas på alla beroenden som anger att de har slutförts. Detta är användbart när klienten inte vill att den överordnade transaktionen ska checkas in förrän de beroende transaktionerna har slutförts. Om det överordnade arbetet avslutas tidigare än den beroende transaktionen och anropar Commit transaktionen blockeras incheckningsprocessen i ett tillstånd där ytterligare arbete kan utföras på transaktionen och nya registreringar kan skapas tills alla beroenden anropar Complete. Så snart alla har slutfört sitt arbete och anropat Completebörjar incheckningsprocessen för transaktionen.

  • RollbackIfNotComplete, å andra sidan, skapar en beroende transaktion som automatiskt avbryter om Commit anropas på den överordnade transaktionen innan Complete anropas. I det här fallet är allt arbete som utförs i den beroende transaktionen intakt inom en transaktionslivslängd och ingen har en chans att checka in bara en del av den.

Metoden Complete får bara anropas en gång när programmet har slutfört sitt arbete med den beroende transaktionen. Annars genereras en InvalidOperationException . När det här anropet har anropats får du inte försöka utföra något ytterligare arbete med transaktionen, eller så utlöses ett undantag.

I följande kodexempel visas hur du skapar en beroende transaktion för att hantera två samtidiga uppgifter genom att klona en beroende transaktion och skicka den till en arbetstråd.

public class WorkerThread  
{  
    public void DoWork(DependentTransaction dependentTransaction)  
    {  
        Thread thread = new Thread(ThreadMethod);  
        thread.Start(dependentTransaction);
    }  
  
    public void ThreadMethod(object transaction)
    {
        DependentTransaction dependentTransaction = transaction as DependentTransaction;  
        Debug.Assert(dependentTransaction != null);
        try  
        {  
            using(TransactionScope ts = new TransactionScope(dependentTransaction))  
            {  
                /* Perform transactional work here */
                ts.Complete();  
            }  
        }  
        finally  
        {  
            dependentTransaction.Complete();
             dependentTransaction.Dispose();
        }  
    }  
  
//Client code
using(TransactionScope scope = new TransactionScope())  
{  
    Transaction currentTransaction = Transaction.Current;  
    DependentTransaction dependentTransaction;
    dependentTransaction = currentTransaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete);  
    WorkerThread workerThread = new WorkerThread();  
    workerThread.DoWork(dependentTransaction);  
    /* Do some transactional work here, then: */  
    scope.Complete();  
}  

Klientkoden skapar ett transaktionsomfång som också anger den omgivande transaktionen. Du bör inte skicka den omgivande transaktionen till arbetstråden. I stället bör du klona den aktuella (omgivande) transaktionen genom att anropa DependentClone metoden för den aktuella transaktionen och skicka den beroende till arbetstråden.

Metoden ThreadMethod körs på den nya tråden. Klienten startar en ny tråd och skickar den beroende transaktionen som ThreadMethod parameter.

Eftersom den beroende transaktionen skapas med BlockCommitUntilCompletegaranteras att transaktionen inte kan genomföras förrän allt transaktionsarbete som utförs på den andra tråden har slutförts och Complete anropas för den beroende transaktionen. Det innebär att om klientens omfång upphör (när det försöker ta bort transaktionsobjektet i slutet av -instruktionen using ) innan den nya tråden anropar Complete den beroende transaktionen, blockeras klientkoden tills den anropas Complete på den beroende. Sedan kan transaktionen slutföra incheckningen eller avbryta.

Samtidighetsproblem

Det finns några ytterligare samtidighetsproblem som du måste känna till när du använder DependentTransaction klassen:

  • Om arbetstråden återställer transaktionen men den överordnade försöker checka in den genereras en TransactionAbortedException .

  • Du bör skapa en ny beroende klon för varje arbetstråd i transaktionen. Skicka inte samma beroende klon till flera trådar, eftersom endast en av dem kan anropa Complete den.

  • Om arbetstråden skapar en ny arbetstråd ska du skapa en beroende klon från den beroende klonen och skicka den till den nya tråden.

Se även