2014-11-27 3 views
2

Я пытаюсь использовать класс TransactionScope для установки определенного тайм-аута для выполнения кода. Более конкретно,Использование TransactionScope для тайм-аута обычного (не связанного с db) кода C#

static void Main(string[] args) 
    { 
     int counter = 0; 
     try 
     { 
      using (var scope = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 0, 5)))     
      { 
       for (int i = 0; i < 50000; i++) 
       { 
        Console.WriteLine("Counter : {0}", counter); 
        counter++; 
        Thread.Sleep(100); 
       } 

       scope.Complete(); 
      } 
     } 
     catch (Exception ex) 
     { 

      Console.WriteLine("Exception : {0}", ex); 
     } 
    } 

После некоторого чтения о TransactionScope, я ожидал бы выше блок кода при помощи заявления будет прервана в течение 5 секунд.

Но это не ведет себя так. Цикл for продолжает действовать независимо от таймаута транзакции (чего я не ожидал). Исполнение для цикла заканчивается, когда я = 50000, и я получаю ниже исключение после того, как с помощью оператор заканчивается:

Exception : System.Transactions.TransactionAbortedException: The transaction has aborted. ---> System.TimeoutException: Transaction Timeout 
    --- End of inner exception stack trace --- 
    at System.Transactions.TransactionStateAborted.BeginCommit(InternalTransaction tx, Boolean asyncCommit, AsyncCallback asyncCallback, Object asyncState) 
    at System.Transactions.CommittableTransaction.Commit() 
    at System.Transactions.TransactionScope.InternalDispose() 
    at System.Transactions.TransactionScope.Dispose() 

Могу ли я делать что-н неправильно? Класс TransactionScope может использоваться только для кода, связанного с db?

Что мне действительно нужно, это какой-то механизм, который должен установить тайм-аут для блока выполнения кода. Я нашел несколько ссылок:

How to set timeout for a line of c# code

Set timeout to an operation

Implement C# Generic Timeout

Все они, кажется, чтобы выполнить тайм-аут, требующий кода в отдельном потоке и прервать эту нить, когда происходит тайм-аут. Однако я думаю, что это грязно, и я не хочу, чтобы это из-за стоимости создания потока и проблемы нити ABORt, как описано здесь:

http://blogs.msmvps.com/peterritchie/2007/08/22/thead-abort-is-a-sign-of-a-poorly-designed-program/

Я думал, что я мог бы использовать объем транзакций тайм-аут любой код блок, но он не ведет себя так.

Какое наилучшее решение установить ограничение на выполнение кода?

+0

Я думаю, вы уже ответили (и отбросили) лучшие варианты для этого. Я предлагаю снова взглянуть на них. – Will

ответ

2

Насколько я знаю, если только блок кода не написан специально, чтобы знать, что он может тайм-аут (например, это петля, проверяющая прошедшее время и, при необходимости, терминирование), невозможно отключить операцию без прерывания нить. Это грязно, как вы уже указали. Если ограничения в кодовом блоке позволяют это (нет состояния), я бы, вероятно, начал отдельный процесс (у них есть пул в моем распоряжении, потому что это дороже, чем создание потоков), чтобы кодовый блок не повлиял ни на что , и запустите там код. Убейте процесс, если код не вернется вовремя. Вниз по этому пути вам придется придумать способ вызова кода, разрешения сборки и т. Д. Возможно, используйте некоторые решения для песочницы ... (Можете использовать AppDomains вместо Processes, но они могут привести к хост-процессу, если вещи идут на юг).

Я не думаю, что TransactionScope является хорошим кандидатом на такую ​​работу.

+1

+1 для вашего последнего комментария! TransactionScope бесполезен для этого и выдает только исключение тайм-аута, когда вызывается .Complete, что может быть намного позже, чем ожидалось, если код внутри блока требует времени для завершения. – Will