Подтвердить что ты не робот

Установите тайм-аут на операцию

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

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

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

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

4b9b3361

Ответ 1

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

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.");
        }
    }
}

Ответ 2

Более просто используя Task.Wait(TimeSpan):

using System.Threading.Tasks;

var task = Task.Run(() => obj.PerformInitTransaction());
if (task.Wait(TimeSpan.FromSeconds(30)))
    return task.Result;
else
    throw new Exception("Timed out");

Ответ 3

Если вы не хотите блокировать основной поток, вы можете использовать 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();
}

Джон Скит имеет менее сильный способ ( "Отключение рабочих тем" Изящно) остановки потока, чем отмена.

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

PerformInitTransaction должен действительно быть тем, который обеспечивает тайм-аут.

Ответ 4

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

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

Ответ 5

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

Ответ 6

Хороший пример универсального решения для этого, используя вспомогательный класс здесь.

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

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