Как я могу разбудить спящий поток в 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, являющийся полем класса, доступным из обоих потоков

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

Другие вопросы по тегам