Как я могу разбудить спящий поток в С#?

Прежде чем люди предложат это: Я не использую 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 дней? Поскольку я не могу контролировать входящие потоки, я не могу знать, и, кажется, нет способа предотвратить подобное...


person Groxx    schedule 31.12.2010    source источник
comment
Как у вас будут ссылки на чужие темы?   -  person Tim Lloyd    schedule 31.12.2010
comment
void myFunc(Thread externalThread){ // прибл. приведенный выше код }   -  person Groxx    schedule 31.12.2010
comment
если это 10-дневное ожидание, сообщите своему руководителю, чтобы разработчика, который сделал это, можно было уволить. Не пытайтесь охватить все возможные идиотизмы некомпетентных разработчиков.   -  person John Saunders    schedule 31.12.2010
comment
Я действительно не вижу, что вы пытаетесь реализовать из вопроса. Это какой-то диспетчер задач? Подробнее пожалуйста.   -  person Tim Lloyd    schedule 31.12.2010
comment
@chibacity: это половина длинной задачи, выполняющей фрагмент кода, поэтому я могу запускать события ajax и опрашивать их ход. Это всеобъемлющий код менеджера.   -  person Groxx    schedule 31.12.2010


Ответы (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();
}
person shf301    schedule 31.12.2010
comment
Так бы и было, если бы я не создавал кучу тем; Мне нужен программный способ остановить их все. Из этого и небольшого эксперимента у меня возник момент: Abort не распространяется. По какой-то причине у меня было в голове, что потоки каким-то образом ограничены тем, где они были запущены, но теперь я понимаю, почему этого не может быть. Спасибо за ответ! - person Groxx; 31.12.2010

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

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

person Cyryl Płotnicki    schedule 08.12.2011