C # Как убить заблокированную нить? - PullRequest
2 голосов
/ 06 апреля 2011

У меня есть тема:

void threadCode(object o)
{
  doStuffHere(o); // Blocking call. Sometimes hangs.
}

и я так называю:

Thread t = new Thread(new ThreadStart(delegate()
  {
    threadCode(o);
  }));
t.Start();

StopWatch sw = new StopWatch();
sw.Start();

while (t.IsAlive)
{
  Application.DoEvents();

  if (sw.EllapsedMilliseconds > myTimeout)
    // Somehow kill t even though doStuffHere(o) is blocked (but hung)
}

Я использую .NET Zip Library и звоню ZipFile.CommitUpdate(), которая работает большую часть времени, но иногда просто зависает. Я не знаю почему, я не вижу ничего в документации, которая указывает, почему это происходит. Небольшой файл, который должен занимать не более 5 - 10 секунд, иногда будет находиться там более 5 минут без прогресса. Графики ввода / вывода в проводнике процессов показывают, что процесс не читает или не записывает данные и не использует процессор. По сути, если это произойдет, я хочу убить CommitUpdate() и повторить попытку один или два раза, прежде чем сдаться.

Есть идеи, как убить поток, застрявший в блокирующем вызове?

(В качестве альтернативы - те из вас, кто имеет опыт работы с этой библиотекой zip: знаете ли вы, почему она иногда зависает с некоторыми файлами? Я изменяю содержимое файлов .docx и .pptx (GZip). Это будет идеальное решение.)

Ответы [ 7 ]

8 голосов
/ 06 апреля 2011

Если вы собираетесь завершить зависание потока с помощью Thread.Abort(), убедитесь, что вы обрабатываете ThreadAbortException в коде потока.Обычный шаблон:

try {
    // do work here
}
catch (ThreadAbortException) {
    // allows your thread to gracefully terminate
    Thread.ResetAbort();
}
catch {
    // regular exception handling
}

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

5 голосов
/ 06 апреля 2011

Вы можете позвонить Thread.Abort, чтобы кроваво убить нить.

Поток не сможет очистить после себя (кроме finally блоков); в зависимости от того, что именно он делал в то время, это может серьезно испортить вашу программу.

2 голосов
/ 09 апреля 2011

НЕ используйте Thread.Abort (), чтобы обойти ошибку в используемой вами библиотеке. (Или это может быть ошибка в вашем коде).

Либо исправьте исходную ошибку, либо перейдите в другую библиотеку.

ps: вы можете попробовать DotNetZip вместо SharpZipLib.

2 голосов
/ 06 апреля 2011

Альтернатива использованию секундомера, вы можете сделать это:

Thread thread = new Thread(new ThreadStart(delegate()
{
   threadCode(o);
}));
thread.Start();

thread.Join(myTimeout);
if(thread.IsAlive)
{
   thread.Abort();
}
1 голос
/ 06 апреля 2011

Используйте метод Thread.Abort (), чтобы убить поток.Подробнее см. http://msdn.microsoft.com/en-us/library/aa332365(VS.71).aspx.

0 голосов
/ 06 апреля 2011

Я сам этого не делал, поэтому не уверен в этом, но разве t.Abort(); помогает?

0 голосов
/ 06 апреля 2011

В качестве последнего средства вы можете использовать Thread.Abort() для завершения потока - не ожидайте какого-либо упорядоченного отключения.

...