Как организовать задержку выполнения программы в C
wikiHow работает по принципу вики, а это значит, что многие наши статьи написаны несколькими авторами. При создании этой статьи над ее редактированием и улучшением работали, в том числе анонимно, 11 человек(а).
Количество просмотров этой статьи: 27 713.
Вы когда-нибудь хотели создать программу на C, которая выжидает определенное время? Вы можете настроить способ, чтобы дать времени «пролететь», например: при показе всплывающей страницы (уведомление или подсказка) для игры. . ОК, вот несколько способов создания программы вида «stand still» (стоять на месте), читайте дальше .
Методы ожидания задачи
В приведенных примерах из предыдущей статьи основной поток исполнения, а по существу, метод Main(), завершался потому, что такой результат гарантировали вызовы метода Thread.Sleep(). Но подобный подход нельзя считать удовлетворительным.
Организовать ожидание завершения задач можно и более совершенным способом, применяя методы ожидания, специально предоставляемые в классе Task. Самым простым из них считается метод Wait(), приостанавливающий исполнение вызывающего потока до тех пор, пока не завершится вызываемая задача.
При выполнении этого метода могут быть сгенерированы два исключения. Первым из них является исключение ObjectDisposedException. Оно генерируется в том случае, если задача освобождена посредством вызова метода Dispose(). А второе исключение, AggregateException, генерируется в том случае, если задача сама генерирует исключение или же отменяется. Как правило, отслеживается и обрабатывается именно это исключение.
В связи с тем что задача может сгенерировать не одно исключение, если, например, у нее имеются порожденные задачи, все подобные исключения собираются в единое исключение типа AggregateException. Для того чтобы выяснить, что же произошло на самом деле, достаточно проанализировать внутренние исключения, связанные с этим совокупным исключением. А до тех пор в приведенных далее примерах любые исключения, генерируемые задачами, будут обрабатываться во время выполнения.
Ниже приведен вариант программы из предыдущей статьи, измененный с целью продемонстрировать применение метода Wait() на практике. Этот метод используется внутри метода Main(), чтобы приостановить его выполнение до тех пор, пока не завершатся обе задачи task1 и task2:

Как следует из приведенного выше результата, выполнение метода Main() приостанавливается до тех пор, пока не завершатся обе задачи task1 и task2. Следует, однако, иметь в виду, что в рассматриваемой здесь программе последовательность завершения задач task и task2 не имеет особого значения для вызовов метода Wait(). Так, если первой завершается задача task2, то в вызове метода task1.Wait() будет по-прежнему ожидаться завершение задачи task1. В таком случае вызов метода task2.Wait() приведет к выполнению и немедленному возврату из него, поскольку задача task2 уже завершена.
В данном случае оказывается достаточно двух вызовов метода Wait(), но того же результата можно добиться и более простым способом, воспользовавшись методом WaitAll(). Этот метод организует ожидание завершения группы задач. Возврата из него не произойдет до тех пор, пока не завершатся все задачи.
Задачи, завершения которых требуется ожидать, передаются с помощью параметра в виде массива tasks. А поскольку этот параметр относится к типу params, то данному методу можно отдельно передать массив объектов типа Task или список задач. При этом могут быть сгенерированы различные исключения, включая и AggregateException.
Организуя ожидание завершения нескольких задач, следует быть особенно внимательным, чтобы избежать взаимоблокировок. Так, если две задачи ожидают завершения друг друга, то вызов метода WaitAll() вообще не приведет к возврату из него.
Разумеется, условия для взаимоблокировок возникают в результате ошибок программирования, которых следует избегать. Следовательно, если вызов метода WaitAll() не приводит к возврату из него, то следует внимательно проанализировать, могут ли две задачи или больше взаимно блокироваться. (Вызов метода Wait(), который не приводит к возврату из него, также может стать причиной взаимоблокировок.)
Иногда требуется организовать ожидание до тех пор, пока не завершится любая из группы задач. Для этой цели служит метод WaitAny(). Ниже приведена простейшая форма его объявления:
Задачи, завершения которых требуется ожидать, передаются с помощью параметра в виде массива tasks объектов типа Task или отдельного списка аргументов типа Task. Этот метод возвращает индекс задачи, которая завершается первой. При этом могут быть сгенерированы различные исключения. Попробуйте применить метод WaitAny() на практике, подставив в предыдущей программе следующий вызов:
Теперь, выполнение метода Main() возобновится, а программа завершится, как только завершится одна из двух задач. Помимо рассматривавшихся здесь форм методов Wait(), WaitAll() и WaitAny(), имеются и другие их варианты, в которых можно указывать период простоя или отслеживать признак отмены.
Метод Dispose()
В классе Task реализуется интерфейс IDisposable, в котором определяется метод Dispose(). Ниже приведена форма его объявления:
Метод Dispose() реализуется в классе Task, освобождая ресурсы, используемые этим классом. Как правило, ресурсы, связанные с классом Task, освобождаются автоматически во время «сборки мусора» (или по завершении программы). Но если эти ресурсы требуется освободить еще раньше, то для этой цели служит метод Dispose(). Это особенно важно в тех программах, где создается большое число задач, оставляемых на произвол судьбы.
Следует, однако, иметь в виду, что метод Dispose() можно вызывать для отдельной задачи только после ее завершения. Следовательно, для выяснения факта завершения отдельной задачи, прежде чем вызывать метод Dispose(), потребуется некоторый механизм, например, вызов метода Wait(). Именно поэтому так важно было рассмотреть метод Wait(), перед тем как обсуждать метод Dispose(). Если же попытаться вызвать Dispose() для все еще активной задачи, то будет сгенерировано исключение InvalidOperationException.
Wait one second in running program
İ want to wait one second before printing my grid cells with this code, but it isn’t working. What can i do?
![]()
12 Answers 12
Is it pausing, but you don’t see your red color appear in the cell? Try this:
![]()
Personally I think Thread.Sleep is a poor implementation. It locks the UI etc. I personally like timer implementations since it waits then fires.
Usage: DelayFactory.DelayAction(500, new Action(() => < this.RunAction(); >));
![]()
Wait function using timers, no UI locks.
Usage: just placing this inside your code that needs to wait:
![]()
.Net Core seems to be missing the DispatcherTimer .
If we are OK with using an async method, Task.Delay will meet our needs. This can also be useful if you want to wait inside of a for loop for rate-limiting reasons.
You can await the completion of this method as follows:
![]()
The Best way to wait without freezing your main thread is using the Task.Delay function.
So your code will look like this
I feel like all that was wrong here was the order, Selçuklu wanted the app to wait for a second before filling in the grid, so the Sleep command should have come before the fill command.
![]()
Busy waiting won’t be a severe drawback if it is short. In my case there was the need to give visual feedback to the user by flashing a control (it is a chart control that can be copied to clipboard, which changes its background for some milliseconds). It works fine this way:
C# Delay – How to pause code execution in C#
When programming, it is common to want to pause execution for a certain amount of time and most common programming and scripting languages have some form of Sleep command built in to achieve this.
For example, when we’ve encountered a problem with a remote resource, it’s common to back-off (pause execution) for a short amount of time and retry.
Here I’ll go through the various options for introducing a delay in C#, ranging from the most basic (Thread.Sleep()) – suitable for use in a single threaded console application. To more complicated versions for use in multi threaded interactive applications.
Add a delay in C# using Thread.Sleep()
Using Thread.Sleep() is the simplest way to introduce a delay in C# code, but it will hang the main thread for the duration of the delay, so it’s only really appropriate for console applications. Assuming you’re happy with that, let’s dive into a more complete example:
A common mistake when first using Thread.Sleep() is to forget the using, result in the following error:
This is easily fixed by adding a “using System.Threading;” line at the top of the file, as in the above example.
The next thing to note is that Thread.Sleep() takes miliseconds as it’s argument, so if you want to sleep for 3 seconds you need to pass the number 3000. It’s possible to make your intent clearer using a timespan like this:
But older versions of Thread.Sleep didn’t take a TimeSpan, so your mileage may vary.
Add a Delay in C# without blocking main thread using Task.Delay()
There is an asynchronous version of Thread.Sleep called Task.Delay. If you’re not familiar with how asynchronous calls work in C# then I’m planning a series of posts on the topic (let me know you want it in the comments!). Until that’s up, see the official docs if you need more info.
The idea here is to start a new task that runs the delay in the background, let’s look at an example:
Once again if you forget the using, you might encounter the following error:
Be sure to add “using System.Threading.Tasks;” to avoid this.
Note also that we’ve had to make our main method async and return a Task rather than void. This is a contrived example, and if you’ve got a console application as simple of this one there’s no need for this asynchronous version (just use sleep). Forgetting to do that can result in this error:
So what can we do with this asynchronous delay that can’t be done with the basic Thread.Sleep()? Quite simply, we can get other things done while we wait for the delay to finish. Time for a further example:
This example makes use of the fact that Task.Delay() is running in the background, and allows the main thread to do some useful (or not!) work. In this example the main thread just outputs “Waiting…
I hope I’ve not confused things by combining both Task.Delay() and Thread.Sleep() in one example!
For interactive (non-console) applications it’s especially important that the main thread can respond to inputs, allowing the program to remain interactive while delays are processed in the background.
Add a repeating delay in C# using one of the Timer classes
There are several timer classes that can be used to repeatedly trigger events after a certain period of time has elapsed:
Each of these timer classes has different functionality, with these remarks on MSDN giving more details of which to use depending on your requirements.
If you just want a single delay in C# then use either Thread.Sleep() or Task.Delay() as described above. However, if you’re after a repeating delay, a timer can be helpful.
For the purposes of the following examples, I’m going to use a System.Threading.Timer() as it appears to be Microsoft preferred general purpose timer.
- callback TimerCallback – this is the method that should be called whenever the timer fires
- dueTime int/Timespan – this is how long to wait before the timer first fires
- period int/TimeSpan – this is how long to wait between each subsequent firing of the timer
As example of such an instantiation might be:
This starts a timer that will wait 5 seconds before calling DoSomething, which it will continue to do once a second after that.
The following example is more complete, showing you how to set up the callback, one way of tracking the number of times it’s called, and how to signal that the timer should finish and then stop it. Here’re the code:
I know it’s a bit heavy, but in the above example I’ve created a new class IdleWaiter which is responsible for printing “Waiting…” each time it’s called, while tracking the number of times it’s been called and signalling (via an autoResetEvent) when it’s reached a threshold.
When you run this code, the timer fires every seconds until it’s been run three times, then it signals that it’s reached it’s threshold and we stop the timer by disposing of it.
If we didn’t dispose of the timer it would keep on ticking once every second. You can try this for yourself by commenting out the dispose line and adding a Thread.Sleep() to stop the program exiting:
If you run the above code with this change you get the following output:
Using a Timer might be the right choice if you want a task to repeat on a schedule, but given the added complexity, I’d probably stick to the other options for most use cases.
Conclusion
If you’re in a console app, or some other single threaded application, you can use Thread.Sleep() to trigger a delay, just be careful with the fact this takes milliseconds (or better yet use TimeSpan.FromSeconds()).
If you want to delay in an asynchronous way, allowing your main thread to do useful work in the interim, Thread.Delay() is they way to go.
If you’re want to kick something off repeatedly with a delay in between, then you should be using a timer like System.threading.Timer.
I’m sure there are other ways of adding a delay in C#, but I think I’ve covered off the most important ones. If there’s something you think I’ve missed that deserved to be included, if you think I’ve got something wrong, or if you just want to congratulate me on a job well done then please let me know in the comments.
Mean while, if you want to go deep on another area of C#, might I recommend my recent post on using (or abusing?) Linq style foreach.