Как я могу разбудить спящий поток в C#?
Прежде чем люди предложат это: я не использую Thread.sleep ни для чего, кроме попыток найти способ обойти это. Я пытаюсь обработать будущий код других людей, который не может быть свободным.Sleep(). Я очень хорошо понимаю, как ужасно синхронизировать вещи.
Я принимаю тему в клочке моего кода. Я хотел бы иметь возможность установить ограничение на время жизни этой темы. Мой обычный способ сделать это выглядит так:
Thread outer = new Thread(() =>
{
externalThread.Start();
externalThread.Join();
});
outer.Start();
outer.Join(lifetime);
if (outer.ThreadState != ThreadState.Stopped)
{
outer.Abort();
}
inner.Join();
С тех пор я обнаружил, что, очевидно, я не могу разбудить спящую нить до того, как сон закончится. Что еще хуже, это все равно пишет в консоль, если я дам ей время жизни 10 миллисекунд:
new Thread(() => { Thread.Sleep(2000); Console.WriteLine("second"); })
Хотя я понимаю, что.Abort() не является жестким ограничением на выполнение потоков. Кажется, 2 секунды было бы достаточно для предупреждения, но я думаю, что нет...
Я попытался проверить состояние WaitSleepJoin и.Interrupt(); он прерывает поток или выдает исключение (извините, не уверен, что. Windows сообщает мне, что произошел сбой, если не запущен отладчик, и если он работает, как будто прерывание не было вызвано), и все еще пишет в консоль через 2 секунды,.Resume(), по-видимому, ничего не делает со спящим потоком.
Есть ли способ разбудить поток, не дожидаясь истечения его сна? Я понимаю, что остановка не является "немедленной", так что Console.WriteLine можно вызывать независимо; это 2 секундное ожидание, которое меня беспокоит. Что если это 10-дневное ожидание? Поскольку я не могу контролировать входящие потоки, у меня нет возможности узнать, и, кажется, нет способа предотвратить такую вещь...
2 ответа
Нет, нет способа вывести нить из сна. Вы можете только прервать поток, вызвав Abort или Interrupt (оба из которых выдают исключение ThreadAbortException).
Но для решения вопроса почему при запуске:
new Thread(() => { Thread.Sleep(2000); Console.WriteLine("second"); })
по-прежнему печатается тайм-аут 10 мс, потому что ваш код для управления временем жизни потока не делает то, что вы хотите.
Итак, у вас есть externalThread и external. Вы запускаете внешний (который запускает новый поток, давайте назовем его потоком 1) и с внешнего вызова запускаем на внешний поток (который запускает новый поток, давайте назовем его потоком 2). Итак, вы только что начали две новые темы.
Когда вы звоните outer.About()
, который прерывает только поток 1. Поток начался с вызова externalThread.Start()
поток 2 продолжает выполнение до завершения, так как ничто не прерывает его.
Я не уверен, что вы пытаетесь достичь с помощью внешней нити. Разве это не будет проще:
externalThread.Start();
externalThread.Join(lifetime);
if (externalThread.ThreadState != ThreadState.Stopped)
{
externalThread.Abort();
}
Используйте WaitOne + таймер для управления потоками неизвестного происхождения.
или если бы вы имели контроль над рабочим кодом потока:
своего рода хакерский способ, чтобы добиться более "отзывчивого сна", когда не нравятся таймеры / другие потоки, используемые для пробуждения потока
используйте его вместо обычного Thread.Sleep
private void WaitFor(int milis)
{
const int interval = 500;
if (milis <= interval)
{
throw new ArgumentException();
}
var sections = milis / interval;
for (var s = 0; s < sections && (!ShouldQuit); ++s)
{
Thread.Sleep(interval);
}
}
обратите внимание на флаг ShouldQuit, являющийся полем класса, доступным из обоих потоков
конечно, это имеет худшие характеристики использования процессора, чем ожидание на основе события / таймера