Тайм-аут набора к операции

У меня есть объект obj который является сторонним компонентом,

// this could take more than 30 seconds
int result = obj.PerformInitTransaction(); 

Я не знаю то, что происходит внутри. То, что я знаю, - то, если это занимает время, это является отказавшим.

как установить механизм тайм-аута к этой операции, так, чтобы, если требуется больше чем 30 секунд, я просто бросил MoreThan30SecondsException ?

41
задан Chris S 15 February 2010 в 12:21
поделиться

5 ответов

Вы можете запустить операцию в отдельном потоке, а затем установить тайм-аут для операции соединения потока:

using System.Threading;

class Program {
    static void DoSomething() {
        try {
            // your call here...
            obj.PerformInitTransaction();         
        } catch (ThreadAbortException) {
            // cleanup code, if needed...
        }
    }

    public static void Main(params string[] args) {

        Thread t = new Thread(DoSomething);
        t.Start();
        if (!t.Join(TimeSpan.FromSeconds(30))) {
            t.Abort();
            throw new Exception("More than 30 secs.");
        }
    }
}
73
ответ дан 27 November 2019 в 00:21
поделиться

Вы должны быть осторожны при прерывании подобной операции, особенно потому, что она находится в стороннем компоненте, который (возможно) не имеет доступа к коду для изменения.

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

2
ответ дан 27 November 2019 в 00:21
поделиться

Если вы не хотите блокировать основной поток, вы можете использовать System.Threading.Timer:

private Thread _thread;

void Main(string[] args)
{
    _thread = new ThreadStart(ThreadEntry);
    _thread.Start();
    Timer timer = new Timer(Timeout,null,30000,Timeout.Infinite);
}


void ThreadEntry()
{
    int result = obj.PerformInitTransaction(); 
}

void TimeOut(object state)
{
    // Abort the thread - see the comments
    _thread.Abort();

    throw new ItTimedOutException();
}

Jon Skeet предлагает менее принудительный способ (Shutting Down Worker Threads Gracefully) остановки потока, чем abort.

Однако, поскольку вы не контролируете операции, которые выполняет PerformInitTransaction(), вы мало что можете сделать, когда Abort не работает и оставляет объект в недопустимом состоянии. Как уже говорилось, если вы можете очистить все, что осталось после прерывания PerformInitTransaction(), вы можете сделать это, поймав ThreadAbortException(), хотя, поскольку это сторонний вызов, это означает угадать состояние, в котором вы оставили их метод.

На самом деле таймаут должен обеспечивать PerformInitTransaction.

7
ответ дан 27 November 2019 в 00:21
поделиться

Есть хороший пример общего решения этой проблемы с использованием вспомогательного класса здесь.

Он использует делегат Action, чтобы избежать создания/уничтожения потоков, показанных в предыдущем примере.

Надеюсь, это поможет.

0
ответ дан 27 November 2019 в 00:21
поделиться

Вы можете посмотреть на вызов метода в потоке и по истечении времени ожидания, прервать поток и вызвать исключение. Кроме того, в этом случае вам придется обработать исключение ThreadBorted.

1
ответ дан 27 November 2019 в 00:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: