Совместное использование объема транзакции между потоками - PullRequest
2 голосов
/ 17 ноября 2010

У меня есть один класс, делающий некоторый код транзакции.
Предположим, что:

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();
        }
    }

Теперь у меня есть несколько потоков, которые исполняют этот код:

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();
}  

Каждый поток создает собственную транзакцию. Как сделать одну и ту же транзакцию между всеми потоками?

Ответы [ 3 ]

6 голосов
/ 01 декабря 2010

Вы можете взглянуть на класс DependentTransaction, который полезен для транзакций в нескольких потоках.См. Документацию .

1 голос
/ 17 ноября 2010

Код, который у вас есть, создаст условия гонки. Вы почти сразу же вызовете scope.complete до того, как завершатся ваши темы.

Однако, даже если каждый работник создает область транзакции, они фактически вкладываются .Net в область транзакции верхнего уровня, если вообще создается новая.

Если вы хотите иметь вложенную многоуровневую транзакцию, возможно, вы захотите создать новую область с помощью ScopeOption.RequiresNew. Но это ответ на реальный вопрос, поэтому вы бы хотели это сделать. Транзакции по своей сути означают, что ваша работа в некотором роде является последовательной или критической, чтобы происходить в определенном порядке. Если вы можете распараллелить работу, тогда попытайтесь делать это в отдельных транзакциях, где это возможно, ограничьте область действия до как можно более короткого промежутка времени, чтобы предотвратить блокировку и т. Д.

0 голосов
/ 18 ноября 2010

Проблема с вашим кодом в том, что вы не ждете, пока все потоки завершат свою работу, прежде чем позвонить:

            transaction.Complete();

Таким образом, любой из ваших потоков может вызвать этот метод до того, как ваша многопоточная транзакция завершится как атомарная. Вам, вероятно, понадобится использовать класс Semaphore, чтобы избежать столкновения.

Кроме того, я хотел бы изучить использование PLinq, если ваша среда это позволяет.

...