Как я могу разбудить спящий поток в C #? - PullRequest
4 голосов
/ 31 декабря 2010

Прежде чем люди предложат это: Я не использую 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 ]

2 голосов
/ 31 декабря 2010

Нет, нет способа вывести нить из сна. Вы можете только прервать поток, вызвав Abort или Interrupt (оба из которых выдают исключение ThreadAbortException).

Но для ответа на вопрос, почему при запуске:

new Thread(() => { Thread.Sleep(2000); Console.WriteLine("second"); })

с 10-миллисекундным тайм-аутом все еще печатается, потому что ваш код для управления временем жизни потока не делает то, что вы хотите.

Итак, у вас есть внешний поток и внешний. Вы запускаете внешний (который запускает новый поток, давайте назовем его потоком 1) и начинаем с внешнего вызова на внешнем потоке (который запускает новый поток, давайте назовем его потоком 2). Итак, вы только что создали две новые темы.

Когда вы вызываете outer.About(), это прерывает только поток 1. Поток запускается с вызова externalThread.Start(), поток 2 продолжает выполняться до завершения, поскольку ничто не прерывает его.

Я не уверен, что вы пытаетесь достичь с помощью внешней нити. Разве это не будет проще:

externalThread.Start();
externalThread.Join(lifetime);
if (externalThread.ThreadState != ThreadState.Stopped)
{
    externalThread.Abort();
}
0 голосов
/ 08 декабря 2011

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

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

...