2014-02-03 2 views
1

У меня есть внешняя dll с некоторыми методами, которые мне нужно вызвать. Кроме того, я хочу иметь возможность настроить тайм-аут для выполнения этих методов, чтобы прервать их, если время выполнения> время ожидания конфигурации. Я называю эти методы решения различных задач, например:Stop Task on long running method

Parallel.ForEach(.... 
{ 
    Func<object> asyncFucntion =() => DynamicCall(method, paramList); 
    IAsyncResult ar = asyncFucntion.BeginInvoke(null, null); 
    if (ar.AsyncWaitHandle.WaitOne(timeout, true)) 
    { 
     return asyncFucntion.EndInvoke(ar); 
    } 
    else 
    { 
     //HERE I NEED to stop DynamicCall. Timeout was EXCEEDED 
    } 
}); 

Теперь у меня есть возможность получить DynamicCall идентификатор темы и прервать его. Есть ли другой способ? Более легкий способ? Я не могу использовать Расторжение ТОКЕШ, так как я не могу изменить внешний Dll

Спасибо, Alex

+0

Если вам нужно резко остановить операцию Прервать это путь (не сделать это, если вы не имеете другой способ) , еще проверить Кооперативное аннулирование –

ответ

0

Aborting нить (особенно пул потоков) является really horrible thing делать. Вы можете просто разрешить каждому вызов asyncFunction естественным образом, не наблюдая его результата в случае тайм-аута. См. "How do I cancel non-cancelable async operations?"

На стороне примечания вы используете довольно неэффективно здесь, операция занимает примерно в два раза больше потоков, чем это действительно необходимо. Без Parallel.ForEach, это может выглядеть, как показано ниже, что является лучшей версией, IMO:

var tasks = methods.Select(method => 
{ 
    Func<object> asyncFunction =() => DynamicCall(method, paramList); 

    var task = Task.Factory.FromAsync(
     (asyncCallback, state) => asyncFunction.BeginInvoke(asyncCallback, state), 
     (asyncResult) => asyncFunction.EndInvoke(asyncResult), 
     null); 

    return Task.WhenAny(task, Task.Delay(timeout)).Unwrap(); 
}); 

Task.WhenAll(tasks).Wait(); // or Task.WaitAll(); 
+0

Спасибо, на второй части согласен, я использую в два раза больше потоков. Но в первую очередь мне действительно нужно закрыть те потоки. Некоторые могут длиться целых 1 час, и они заканчиваются заполнением памяти. –

+0

Нет проблем. Боюсь, вам придется согласиться и на первую часть. 'BeginInvoke' использует поток пула, а вызов' Abort' в потоке пула - очень плохая идея: http://stackoverflow.com/q/2335238/1768303 – Noseratio

+0

@AlexandruTata, вам следует рассмотреть возможность использования вспомогательного процесса для размещения вашего «BeginInvoke» (отдельный EXE). Вы можете убить его и перезапустить, если это необходимо, гораздо приятнее, чем убивать потоки внутри вашего собственного процесса. – Noseratio