Приостановка метода для набора # миллисекунд

Мне нужно сделать своего рода" тайм-аут " или паузу в моем методе в течение 10 секунд (10000 миллисекунд), но я не уверен, что следующее будет работать, поскольку у меня нет многопоточности.

Thread.Sleep(10000);

Я попытаюсь использовать этот текущий код, но я был бы признателен, если бы кто-то мог объяснить лучший и правильный способ сделать это, особенно если приведенный выше код не работает должным образом. Спасибо!

обновление: эта программа на самом деле консольное приложение, которое в рассматриваемая функция выполняет много HTTPWebRequests на одном сервере, поэтому я хочу задержать их на определенное количество миллисекунд. Таким образом, обратный вызов не требуется - все, что нужно, это "безусловная пауза" - в основном все это останавливается на 10 секунд, а затем продолжает идти. Я рад, что C# все еще рассматривает это как поток, поэтому поток.Сон.(..) будет работать. Спасибо всем!

7 ответов


вы не можете иметь multi-threading, но вы все еще выполняете в потоке: весь код выполняется в потоке.

вызов Thread.Sleep действительно приостановит текущий поток. Вы действительно хотите, чтобы он безоговорочно приостановился на 10 секунд, или вы хотите, чтобы вас "разбудило" что-то еще? Если вы используете только один поток, вызывая Sleep вполне может быть лучший путь вперед, но это будет зависеть от ситуации.

In в частности, если вы пишете приложение GUI вы не хотите использовать Thread.Sleep из потока пользовательского интерфейса, так как в противном случае все ваше приложение будет не реагировать в течение 10 секунд.

Если вы смогли дать больше информации о вашем применении, то это помогло бы нам посоветовать вас лучше.


это действительно приостановит выполнение потока / метода на 10 секунд. Вы видите конкретную проблему?

обратите внимание, что вы не должны Sleep поток пользовательского интерфейса-было бы лучше сделать обратный вызов вместо этого.

обратите внимание также, что есть другие способы блокировки потока, которые позволяют более простой доступ, чтобы получить его снова (если вы найдете, что это нормально после 2s); например Monitor.Wait(obj, 10000) (другого потока Pulse если нужно, чтобы разбудить его):

static void Main() {
    object lockObj = new object();
    lock (lockObj) {
        new Thread(GetInput).Start(lockObj);
        Monitor.Wait(lockObj, 10000);
    }
    Console.WriteLine("Main exiting");
}
static void GetInput(object state) {
    Console.WriteLine("press return...");
    string s = Console.ReadLine();
    lock (state) {
        Monitor.Pulse(state);
    }
    Console.WriteLine("GetInput exiting");
}

вы можете сделать это с Thread.Interrupt тоже, но ИМО это Мессье.


для этого можно использовать отдельный поток:

   ThreadPool.QueueUserWorkItem(
       delegate(object state)
       {
           Thread.Sleep(1000);
           Console.WriteLine("done");
       });

но, если это приложение Windows Forms, вам нужно будет вызвать код после задержки из потока Gui (эта статья, например: Как обновить GUI из другого потока в C#?).

[Edit] только что видел ваше обновление. Если это консольное приложение, то это сработает. Но если вы до сих пор не использовали несколько потоков, то вам нужно знать, что этот код будет выполняется в другом потоке, что означает, что вам придется позаботиться о проблемах синхронизации потоков.

Если вам не нужны фоновые работники, придерживайтесь "держать его простым".


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

class PauseClass
{
    //(C) Michael Roberg
    //Please feel free to distribute this class but include my credentials.

    System.Timers.Timer pauseTimer = null;

    public void BreakPause()
    {
        if (pauseTimer != null)
        {
            pauseTimer.Stop();
            pauseTimer.Enabled = false;
        }    
    }

    public bool Pause(int miliseconds)
    {
        ThreadPriority CurrentPriority = Thread.CurrentThread.Priority;

        if (miliseconds > 0)
        {
            Thread.CurrentThread.Priority = ThreadPriority.Lowest;

            pauseTimer = new System.Timers.Timer();
            pauseTimer.Elapsed += new ElapsedEventHandler(pauseTimer_Elapsed);

            pauseTimer.Interval = miliseconds;
            pauseTimer.Enabled = true;

            while (pauseTimer.Enabled)
            {
                Thread.Sleep(10);
                Application.DoEvents();
                //pausThread.Sleep(1);
            }

            pauseTimer.Elapsed -= new ElapsedEventHandler(pauseTimer_Elapsed);
        }

        Thread.CurrentThread.Priority = CurrentPriority;

        return true;
    }

    private void pauseTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        pauseTimer.Enabled = false;
    }
}

Да, это работает просто отлично.

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


нить.Сон прекрасен, и AFAIK правильный путь. Даже если вы не Многопоточны: всегда есть хотя бы одна нить, и если вы отправляете ее спать, она спит.

другую (плохо) как является spinlock, например:

// Do never ever use this
private void DoNothing(){ }

private void KillCPU()
{
    DateTime target = DateTime.Now.AddSeconds(10);
    while(DateTime.Now < target) DoNothing();
    DoStuffAfterWaiting10Seconds();
}

это, к сожалению, все еще используется людьми, и, хотя он остановит вашу программу на 10 секунд, она будет работать при 100% использовании процессора (ну, на многоядерных системах это одно ядро).


для тайм-аута у вас должно быть статическое волатильное логическое поле класса isRunning. При запуске нового потока isRunning должен стать true, а в конце-false.

основной поток должен иметь метод, который выполняет циклы для isRunning во время тайм-аута, который вы определяете. Когда тайм-аут заканчивается, вы должны реализовать логику. Но никогда не используйте метод abort thread.

пауза... нет простого решения. Это зависит от того, что вы делаете внутри нити. Однако вы можете посмотреть на монитор.Ждать.