Как приостановить работу программы на время с

Предлагаю такое:

#include <iostream>  
#include <ctime>

using namespace std;

int main() {  
    double tim;  
    tim = time(0);  
    while(time(0) - tim != 2) { }  
    cout << "hello world"!;  
    while (time(0) - tim != 2) { }  
}

Есть еще варианты?

Abyx's user avatar

Abyx

30.8k13 золотых знаков95 серебряных знаков154 бронзовых знака

задан 31 июл 2011 в 12:21

sudo97's user avatar

5

#include <unistd.h>
...
...
sleep(2);//2 секунды
usleep(1000000);//1 секунда (1.000.000 микросекунд)

Необходимо учесть, что проверяя эти функции printf-ом нужно либо закончить принт на "n", либо установить сразу после принта flush: fflush(stdout);, например:

printf("1");
fflush(stdout);
sleep(1);
printf(" - 2");

Это же касается и cout. Аналог fflush(stdout) — cout.flush();

PS В Windows этого дела нет, но есть замена:

#include <windows.h>
Sleep(1000);//1 секунда - 1.000 миллисекунд

ответ дан 31 июл 2011 в 12:35

ivkremer's user avatar

ivkremerivkremer

2,79813 серебряных знаков17 бронзовых знаков

15

Каноничный С++ способ — это использование std::this_thread::sleep_for

#include <chrono>
#include <thread>

int main() {
  std::this_thread::sleep_for(std::chrono::seconds(2));
}

Начиная с C++14 можно писать

using namespace std::literals;
std::this_thread::sleep_for(2s);

ответ дан 30 авг 2015 в 11:19

Abyx's user avatar

AbyxAbyx

30.8k13 золотых знаков95 серебряных знаков154 бронзовых знака

1

  1. sleep()и delay() — из стандартной си’шной библиотек (не помню из какой именно),
  2. Sleep() — WinAPI из windows.h
  3. Использовать для задержки циклы for, while.
    Так же слышал ещё есть функция wait();

ответ дан 1 авг 2011 в 18:26

Alexey Emelyanenko's user avatar

Alexey EmelyanenkoAlexey Emelyanenko

5913 золотых знака18 серебряных знаков43 бронзовых знака

ответ дан 14 авг 2011 в 12:35

Александр Кавокин's user avatar

Александр КавокинАлександр Кавокин

1672 золотых знака4 серебряных знака15 бронзовых знаков

#include <iostream>    
int main(){

    using namespace std;
        for (float ex = 0; ex <=4; ex=ex+0.10) {
           system("cls");
           cout<<"Exit through 4 second"<<endl;
           cout<<" ";
                     }
          exit(0);

    return 0;

}

Как вариант)

Grundy's user avatar

Grundy

79.6k9 золотых знаков74 серебряных знака132 бронзовых знака

ответ дан 8 янв 2017 в 9:42

Влад Красношапка's user avatar

1

riotel

8 / 8 / 4

Регистрация: 23.07.2012

Сообщений: 261

1

Приостановить работу метода на секунду

24.01.2015, 21:50. Показов 10855. Ответов 7

Метки нет (Все метки)


Нужно приостановить работу метода на одну секунду, подскажите как?

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            start();
        }
 
        static void start()
        {
            //приостановить работу на секунду
            start();
        }
    }
}



0



Storm23

Эксперт .NETАвтор FAQ

10370 / 5101 / 1824

Регистрация: 11.01.2015

Сообщений: 6,226

Записей в блоге: 34

24.01.2015, 21:54

2

C#
1
Thread.Sleep(1000);



1



insite2012

Эксперт .NET

5474 / 4244 / 1211

Регистрация: 12.10.2013

Сообщений: 12,248

Записей в блоге: 2

24.01.2015, 21:55

3

Цитата
Сообщение от riotel
Посмотреть сообщение

приостановить работу метода на одну секунду

Так?

C#
1
Thread.Sleep(1000);



1



8 / 8 / 4

Регистрация: 23.07.2012

Сообщений: 261

24.01.2015, 22:40

 [ТС]

4

А есть ли другие способы кроме этого?. Хотел попробовать обойтись без потоков.



0



Эксперт .NETАвтор FAQ

10370 / 5101 / 1824

Регистрация: 11.01.2015

Сообщений: 6,226

Записей в блоге: 34

24.01.2015, 22:45

5

Без потоков не получится, вы уже работаете в потоке )



0



Эксперт .NET

5474 / 4244 / 1211

Регистрация: 12.10.2013

Сообщений: 12,248

Записей в блоге: 2

24.01.2015, 22:49

6

Лучший ответ Сообщение было отмечено riotel как решение

Решение

Цитата
Сообщение от riotel
Посмотреть сообщение

А есть ли другие способы кроме этого?.

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



0



8 / 8 / 4

Регистрация: 23.07.2012

Сообщений: 261

24.01.2015, 22:53

 [ТС]

7

Спасибо понял. Но по иронии этот метод самый основной который будет руководить другими методами.



0



Robar

21 / 21 / 12

Регистрация: 08.01.2015

Сообщений: 66

25.01.2015, 09:01

8

Еще вариант, хотя тоже не айс —

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    public partial class MainForm : Form
    {
        Semaphore sema;
        public MainForm()
        {
            InitializeComponent();
            sema = new Semaphore(1,2);
            sema.WaitOne();
            Start();
        }
        void Start()
        {
            sema.WaitOne(1000);
            MessageBox.Show("Here it comes!");
        }
    }



1



Добавлено 29 мая 2021 в 19:48

Последняя категория инструкций управления порядком выполнения программы, которую мы рассмотрим, – это остановки. Остановка – это инструкция управления порядком выполнения программы, которая завершает программу. В C++ остановки реализованы как функции (а не как ключевые слова), поэтому наши инструкции остановки будут вызовами функций.

Давайте сделаем небольшой экскурс и вспомним, что происходит, когда программа завершается нормально. Когда функция main() завершается (либо достигая конца тела функции, либо с помощью инструкции return), происходит ряд разных вещей.

Во-первых, поскольку мы выходим из функции, все локальные переменные и параметры функции уничтожаются (как обычно).

Затем вызывается специальная функция std::exit() со значением, возвращаемым из main() (код состояния), переданным в качестве аргумента. Так что же такое std::exit()?

Функция std::exit()

std::exit() – это функция, которая вызывает нормальное завершение программы. Нормальное завершение означает, что программа завершилась ожидаемым образом. Обратите внимание, что термин «нормальное завершение» ничего не говорит о том, была ли работа программы успешной (для этого нужен код состояния). Например, предположим, что вы пишете программу, в которой ожидаете, что пользователь введет имя файла для обработки. Если пользователь ввел недопустимое имя файла, ваша программа, вероятно, вернет ненулевой код состояния, чтобы указать на состояние сбоя, но это всё равно будет нормальное завершение.

std::exit() выполняет ряд функций очистки. Сначала уничтожаются объекты со статической продолжительностью хранения. Затем выполняется дополнительная очистка файлов, если использовались какие-либо файлы. Наконец, управление возвращается обратно в ОС, а аргумент, переданный в std::exit(), используется в качестве кода состояния.

Явный вызов std::exit()

Хотя std::exit() при завершении функции main() вызывается неявно, она также может быть вызвана явно, чтобы остановить программу до того момента, как она завершится нормально. Когда std::exit() вызывается таким образом, вам нужно будет включить заголовок cstdlib.

Вот пример явного использования std::exit():

#include <cstdlib> // для std::exit()
#include <iostream>
 
void cleanup()
{
    // здесь идет код для выполнения любой необходимой очистки
    std::cout << "cleanup!n";
}
 
int main()
{
    std::cout << 1 << 'n';
    cleanup();
 
    std::exit(0); // завершаем работу и возвращаем операционной системе код состояния 0
 
    // следующие инструкции никогда не выполняются
    std::cout << 2 << 'n';
 
    return 0;
}

Эта программа печатает:

1
cleanup!

Обратите внимание, что инструкции после вызова std::exit() никогда не выполняются, потому что программа уже завершена.

Хотя в приведенной выше программе мы вызываем std::exit() из функции main(), std::exit() можно вызвать из любой функции для завершения программы в необходимой точке.

Одно важное замечание о явном вызове std::exit(): std::exit() не очищает никакие локальные переменные (ни в текущей функции, ни в функциях вверх по стеку вызовов). По этой причине обычно лучше избегать вызова std::exit().

Предупреждение


Функция std::exit() не очищает локальные переменные в текущей функции и в функциях выше по стеку вызовов.

std::atexit

Поскольку std::exit() завершает программу немедленно, вы можете перед завершением выполнить какую-либо очистку вручную (в приведенном выше примере мы вручную вызывали функцию cleanup()). Поэтому программисту необходимо не забывать вручную вызывать функцию очистки перед каждым вызовом exit().

Чтобы помочь в этом, C++ предлагает функцию std::atexit(), которая позволяет вам указать функцию, которая будет автоматически вызываться при завершении программы через std::exit().

#include <cstdlib> // для std::exit()
#include <iostream>
 
void cleanup()
{
    // здесь идет код для выполнения любой необходимой очистки
    std::cout << "cleanup!n";
}
 
int main()
{
    std::atexit(cleanup); // регистрируем cleanup() для автоматического
                          // вызова при вызове std::exit()
 
    std::cout << 1 << 'n';
 
    std::exit(0); // завершаем работу и возвращаем операционной системе код состояния 0
 
    // следующие инструкции никогда не выполняются
    std::cout << 2 << 'n';
 
    return 0;
}

Эта программа имеет тот же вывод, что и предыдущий пример:

1
cleanup!

Так зачем вам это делать? Это позволяет вам указать функцию очистки в одном месте (возможно, в main), а затем не беспокоиться о том, чтобы не забыть вызвать эту функцию явно перед вызовом std::exit().

Несколько замечаний о std::atexit() и функции очистки: во-первых, поскольку std::exit() вызывается неявно при завершении main(), если программа завершается таким образом, это вызовет любые функции, зарегистрированные std::atexit(). Во-вторых, регистрируемая функция не должна принимать никаких параметров и должна не иметь возвращаемого значения. Наконец, с помощью std::atexit() вы можете зарегистрировать несколько функций очистки, если хотите, и они будут вызываться в порядке, обратном порядку регистрации (последняя зарегистрированная будет вызываться первой).

Для продвинутых читателей


В многопоточных программах вызов std::exit() может привести к сбою вашей программы (поскольку поток, вызывающий std::exit(), будет очищать статические объекты, к которым могут обращаться другие потоки). По этой причине в C++ появилась еще одна пара функций, которые работают аналогично std::exit() и std::atexit(), – std::quick_exit() и std::at_quick_exit(). std::quick_exit() завершает программу нормально, но не очищает статические объекты и может выполнять или не выполнять другие типы очистки. std::at_quick_exit() выполняет ту же роль, что и std::atexit() для программ, завершаемых с помощью std::quick_exit().

std::abort и std::terminate

C++ также содержит две другие функции, связанные с остановкой.

Функция std::abort() вызывает аварийное завершение вашей программы. Аварийное завершение означает, что в программе произошла какая-то необычная ошибка времени выполнения, и программа не может продолжать работу. Например, к аварийному завершению попытка разделить на 0 приведет. std::abort() не выполняет никакой очистки.

#include <cstdlib> // for std::abort()
#include <iostream>
 
int main()
{
    std::cout << 1 << 'n';
    std::abort();
 
    // следующие инструкции никогда не выполняются
    std::cout << 2 << 'n';
 
    return 0;
}

Случаи, когда std::abort вызывается неявно, мы увидим в этой главе позже (7.17 – assert и static_assert).

Функция std::terminate() обычно используется вместе с исключениями (мы рассмотрим исключения в следующей главе). Хотя std::terminate можно вызвать явно, она чаще вызывается неявно, когда исключение не обрабатывается (и в некоторых других случаях, связанных с исключениями). По умолчанию std::terminate() вызывает std::abort().

Когда следует использовать остановки?

Короткий ответ: «почти никогда». В C++ уничтожение локальных объектов является важной частью C++ (особенно когда мы дойдем до классов), и ни одна из вышеупомянутых функций не очищает локальные переменные. Исключения – лучший и безопасный механизм обработки ошибок.

Лучшая практика


Используйте остановки только в том случае, если нет безопасного способа нормально вернуться из функции main. Если вы не отключили исключения, используйте их для безопасной обработки ошибок.

Теги

C++ / CppLearnCppstd::abort()std::at_quick_exit()std::atexit()std::exit()std::quick_exit()std::terminate()STL / Standard Template Library / Стандартная библиотека шаблоновДля начинающихОбучениеПрограммирование

В данной статье мы расскажем, что такое потоки в C#, приоритеты потоков и их типы, покажем, как работать с потоками и как ими управлять, создадим несколько наглядных примеров, объясняющих их работу.

Оглавление:
 Что такое потоки в C#
 Реализация потоков в C#
   — Как создавать потоки в C#
   — Как запускать потоки в C#
   — Как приостановить потоки в C#
   — Приоритеты потоков в C#
   — Изменение типов потоков в C#
 Примеры работы потоков в C#
   — Программа №1: как работают потоки в C#
   — Программа №2: приоритеты потоков в C#
   — Программа №3: типы потоков в C#

Что такое потоки в C#

Если говорить простым языком, то поток — это некая независимая последовательность инструкций для выполнения того или иного действия в программе. В одном конкретном потоке выполняется одна конкретная последовательность действий.
Совокупность таких потоков, выполняемых в программе параллельно называется многопоточностью программы.

Следует также запомнить, что в действительности потоки выполняются всё-таки не совсем параллельно. Дело в том, что процессор физически не может обрабатывать параллельно несколько инструкций или процессов. Однако его вычислительной мощи хватает настолько, что он может выполнять все операции по небольшому фрагменту по очереди, отводя на каждый такой фрагмент по очень маленькому кусочку времени, настолько, что кажется, будто все процессы в компьютере выполняются параллельно.

Точно такая же ситуация происходит и с потоками. Если в программе имеется 3 потока, то сначала выполняется кусочек кода из одного потока, потом кусочек кода из другого, затем — из третьего, после чего процессор снова переходит к какому-либо из двух других потоков. Выбор, какой поток необходимо назначить для выполнения в данный момент остаётся за процессором. Происходит это в доли миллисекунд, поэтому происходит ощущение параллельной работы потоков.

Стандартно в проектах Visual Studio существует только один основной поток — в методе Main. Всё, что в нём выполняется — выполняется последовательно строка за строкой. Но при необходимости можно «распараллелить» выполняемые процессы при помощи потоков.

Для лучшего осознания можно представить следующий пример. Допустим, что наша программа и данные, которые в ней содержатся — это офис с различными предметами (папками, столами, стульями, ручками), а потоки — это работники данного офиса (изначально у нас только один работник, выполняющий всю работу), и каждый работник занимается теми делами, которые ему было сказано выполнять. Работники могут выполнять одинаковые задания, а могут и различные. В случае выполнения какой-либо одной задачи, несколько работников справятся быстрее, чем один.

Например, если один работник будет собирать шкаф час, то вдвоём они могут управиться уже за полчаса. Однако не стоит переусердствовать в количестве работников (потоков). Математически, если нанять 4 работника, то шкаф соберется за 15 минут, если нанять 60 работников — за 1 минуту, а если нанять 3600, то вообще за секунду, но ведь на деле это неверно. Работники будут только мешать друг другу, толкаться, отнимать друг у друга детали, и процесс сборки шкафа может затянуться очень надолго.

Так же и с потоками. Чем больше потоков, тем выше вероятность, что они будут мешать друг другу выполнять свою работу. Например, если заставить работать огромное количество потоков с одними и теми же данными, потокам придётся выстраиваться в очередь для их обработки (например, если тем же 3600 рабочим дать какое-либо письменное задание, но предоставить им для этого дела всего одну ручку, то работникам, естественно, придётся становиться друг за другом в очередь за ручкой, чтобы после её получения выполнить поставленную задачу. Времени это займёт довольно много).

Итог: потоки надо распределять с умом и исключительно в случаях, когда это действительно необходимо для ускорения работы программы либо для повышения производительности.

Язык C#  имеет встроенную поддержку многопоточности, а среда .NET Framework предоставляет сразу несколько классов для работы с потоками, что в купе очень помогает гибко и правильно реализовывать и настраивать многопоточность в проектах.

В среде .NET Framework существует два типа потоков: основной и фоновый (вспомогательный). В целом отличие между ними одно — если первым завершится основной поток, то фоновые потоки в его процессе будут также принудительно остановлены, если же первым завершится фоновый поток, то это не повлияет на остановку основного потока — тот будет продолжать функционировать до тех пор, пока не выполнит всю работу и самостоятельно не остановится. Обычно при создании потока ему по-умолчанию присваивается основной тип. О том, как узнать, к какой разновидности относится тот или иной поток, как придать потоку нужный тип, что такое приоритеты и как их устанавливать, и как в целом работать с потоками в C# мы поговорим ниже.

Реализация потоков в C#

Как создавать потоки в C#

Перво-наперво для работы с потоками в C# необходимо подключить специальную директиву:

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

Дальше стоит понять, что любой поток в C# должен обязательно происходить в каком-либо методе или функции, поэтому для работы с новым потоком необходимо сначала создать для него, например, метод, который и будет точкой входа для этого потока.

Для примера создадим пустой метод под именем fornewthread, который ничего не возвращает:

        static void fornewthread()

        {

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

        }

Теперь мы можем создать сам поток (например, в главном методе Main). Назовём его mythread:

Thread mythread = new Thread(fornewthread);

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

Как запускать потоки в C#

Потоки в C# начинают выполняться не сразу после их инициализации. Каждый из созданных потоков необходимо сначала запустить. Делается это следующим образом: имя_потока.Start();. В случае из нашего примера строка запуска будет такой:

Мы записали данный код, также как и предыдущий, в методе Main сразу после инициализации самого потока. Теперь, при запуске программы, как только в Main выполнится метод Start(), начнёт работать вновь созданный поток. После того, как выполнился Start(), работа программы «распараллеливается»: один поток начинает выполнять код из метода fornewthread, а второй поток продолжает выполнять операции, которые остались ещё не выполненными в методе Main (после Start()). Естественно, это всё произойдёт, если в fornewthread или в Main имеется дополнительный код. Если же один из потоков выполнит работу раньше другого, то первый будет ожидать окончания выполнения работы последнего. А делать это он будет по причине, описанной выше: так как оба потока являются основными, то завершение какого-либо одного потока не влияет на завершение другого. Если бы один из наших потоков был фоновым и «задержался» бы с работой, то при окончании работы основного потока, принудительно завершился бы и он.

Как приостановить потоки в C#

Иногда бывают такие сценарии, когда необходимо бывает приостановить поток, например для того, чтобы пропустить другие потоки и не мешать им выполнять свою работу, либо для снижения потребления процессорного времени.

Есть несколько способов остановки потоков, но в данной статье мы рассмотрим наиболее употребляемый:

В этой строке мы указали, что поток, к которому будет относиться данная инструкция, будет приостановлен на 100 миллисекунд. Как нетрудно догадаться после такого объяснения, значение в скобках указывает, на какой период времени в миллисекундах будет приостановлен поток. Как только заданное время пройдёт, поток снова возобновит свою работу и продолжит с места, на котором остановился. Кстати говоря, число, заданное в скобках — это количество миллисекунд для задержки в идеале, на практике поток может возобновиться на несколько миллисекунд позже или раньше, это зависит не только от программы, но и от характеристик операционной системы.

В метод Sleep также можно передать и значение ноль:

В таком случае поток приостановится на положенный ему интервал времени (мы же помним, что все потоки выполняются по кусочку и по очереди, и при этом на каждый такой кусочек выделяется очень небольшое количество времени, но достаточное для того, чтобы выполнить некоторое количество действий), который он «отдаёт» любому другому готовому к выполнению потоку с таким же приоритетом, как и у него (про приоритеты поговорим ниже). Если же не удастся найти ни один такой «ожидающий» поток, то выполнение текущего потока не будет приостановлено, и он продолжит свою работу.

Приоритеты потоков в C#

Когда в программе фигурирует несколько потоков, выбор процессором следующего потока для выполнения не является рандомным. Дело в том, что у каждого потока имеется значение приоритета, чем выше приоритет потока, тем важнее для процессора предоставить время и ресурсы для выполнения именно ему. Если же приоритет потока не слишком высокий, значит он может и подождать в очереди, пока выполняются более приоритетные потоки.

Всего существует пять вариантов приоритетов потоков в C#:

  • Highest — самый высокий
  • AboveNormal — выше среднего
  • Normal — стандартный
  • BelowNormal — ниже среднего
  • Lowest — самый низкий

Как уже было сказано, чем выше приоритет, тем быстрее он выполнится, опережая потоки с меньшим значением. Если у потоков одинаковые приоритеты, они выполняются по очереди.

По умолчанию все создаваемые потоки в C# имеют стандартный приоритет Normal. Однако приоритеты потоков можно и менять, делается это так:

имяпотока.Priority = ThreadPriority.вариантприоритета;

Допустим мы решили присвоить описанному выше потоку mythread самый высокий приоритет. В таком случае нам надо записать (где-нибудь перед методом Start):

mythread.Priority = ThreadPriority.Highest;

Если же решим присвоить приоритет чуть ниже, чем стандартный, то, соответственно строка будет такой:

mythread.Priority = ThreadPriority.BelowNormal;

Тогда выполнение данного потока будет происходить после выполнения потоков с более высоким приоритетом.

Примечание: приоритет метода Main изменить нельзя. Он всегда будет в позиции Normal.

Простую программу, показывающую на практике необходимость ввода приоритетов можно будет посмотреть в соответствующем разделе ниже.

Изменение типов потоков в C#

Как мы рассказывали выше, потоки в C# бывают основными и фоновыми. Также мы говорили о том, что при создании потока он по умолчанию становится основным. Однако его тип можно, также как и приоритет, поменять. Для того, чтобы сделать основной поток фоновым, нужно изменить его свойство IsBackground: имя_потока.IsBackground = true;

mythread.IsBackground = true;

Если установить данное свойство в значение true, то поток будет работать как фоновый, если в значение false — как основной.

Однако, если в программе используется несколько потоков, то не всегда можно понять, какой поток к какому типу относится. Но, к счастью, всегда можно легко это узнать:

bool a = mythread.IsBackground;

Console.WriteLine(a);

Надо всего-навсего присвоить переменной типа bool значение данного свойства, и, если необходимо, вывести полученное значение на экран. Суть такая же: если выведется true, значит поток фоновый, иначе — основной.

Примеры работы потоков в C#

В данном разделе мы на практике увидим, как работают потоки в C# и создадим для наглядного примера пару простеньких программок.

Программа №1: как работают потоки в C#

В первой программе мы просто реализуем работу нескольких параллельных потоков и особое внимание обратим на выходные данные. Для примера создадим проект C# с тремя потоками, каждый из которых будет выводить числа от 0 до 9.
Вот его код:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

        static void mythread1()

        {

            for (int i = 0; i < 10; i++)

            {

                Console.WriteLine(«Поток 1 выводит « + i);

            }

        }

        static void mythread2()

        {

            for (int i = 0; i < 10; i++)

            {

                Console.WriteLine(«Поток 2 выводит « + i);

            }

        }

        static void Main(string[] args)

        {

            Thread thread1 = new Thread(mythread1);

            Thread thread2 = new Thread(mythread2);

            thread1.Start();

            thread2.Start();

            for (int i = 0; i < 10; i++)

            {

                Console.WriteLine(«Поток 3 выводит « + i);

            }

            Console.ReadLine();

        }

Итак, как мы помним, для того, чтобы инициализировать потоки в C#, нам необходимы методы, в которых они будут выполняться.

Поэтому мы создали два дополнительных метода mythread1 и mythread2, в которых будут выполняться соответственно потоки thread1 и thread2. Третий поток у нас будет работать непосредственно в методе Main.

Мы инициализировали все потоки (третий поток заработал с самого запуска программы, его не надо инициализировать и начинать, естественно), затем запускаем их. В каждой функции происходит одно и то же действие — вывод в консоль цифр от 0 до 9, и при этом каждый поток получил от нас нумерацию от 1 до 3 для удобства восприятия.
Пора запустить программу и посмотреть, что она нам выведет:

Потоки в C# для начинающих: разбор, реализация, примеры

На примере данного скриншота мы можем увидеть «последовательность» многопоточности. Как уже несколько раз было сказано выше, процессор выполняет по кусочку от одного потока, затем кусочек от другого, потом от третьего и так далее.

Здесь мы видим, что процессор сначала предоставил работу третьему потоку (тот вывел первые 7 цифры), затем перешёл к первому потоку (вывел все 10 цифр и прекратил работу), потом выделил ресурсы для второго (успел вывести 9 цифр), затем опять вернул управление третьему потоку (вывел оставшиеся 3 цифры, прекратил работу), а потом опять вернулся ко второму (вывел последнюю цифру). Если мы запустим программу ещё раз, то распределение ресурсов среди потоков может уже измениться и вывод будет происходить как-нибудь иначе, в третий раз — опять по-другому (стоит заметить, что такой «рандом» возможен во многом потому, что все три потока имеют один приоритет — Normal, и, кроме того, все они являются основными потоками). Также стоит заметить, что с самого начала работы программы начинает выполняться поток в методе Main, поэтому он будет чаще других фигурировать на первых местах, несмотря на то, что по коду он запускает цикл последним. Процессор за отведенное на данный поток время обычно успевает не только запустить остальные потоки, но и также вывести несколько цифр (или даже все), прежде чем отведенный для третьего потока промежуток времени закончится.

Для примера мы ещё три раза запустим программу и при каждом выполнении зафиксируем полученные данные:

Потоки в C# для начинающих: разбор, реализация, примеры

Как и было сказано, каждый раз ресурсы, разделяемые процессором между потоками меняются.
 Вы также можете скачать исходный код данной программы и сами попробовать проанализировать работу потоков:

Скачать исходник

Теперь давайте на примере этой же программы попробуем поэкспериментировать с приоритетами и типами потоков.

Программа №2: приоритеты потоков в C#

Теперь давайте посмотрим, на что влияет приоритетность потоков в C#. Мы решили взять для примера программу с тремя потоками, каждый из которых будет выводить в консоль цифры от 0 до 9, от 10 до 19 и от 20 до 29 соответственно. Поставим перед собой задачу вывести в консоль все эти числа последовательно от 0 до 29.

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

Потоки в C# для начинающих: разбор, реализация, примеры

Попробуем реализовать всё так, чтобы у нас получился необходимый нам результат.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

        static void mythread1()

        {

            for (int i = 0; i < 10; i++)

            {

                Console.WriteLine(«Поток 1 выводит « + i);

            }

        }

        static void mythread2()

        {

            for (int i = 10; i < 20; i++)

            {

                Console.WriteLine(«Поток 2 выводит « + i);

            }

        }

        static void mythread3()

        {

            for (int i = 20; i < 30; i++)

            {

                Console.WriteLine(«Поток 3 выводит « + i);

            }

        }

        static void Main(string[] args)

        {

            Thread thread1 = new Thread(mythread1);

            Thread thread2 = new Thread(mythread2);

            Thread thread3 = new Thread(mythread3);

            thread1.Priority = ThreadPriority.Highest;

            thread2.Priority = ThreadPriority.AboveNormal;

            thread3.Priority = ThreadPriority.Lowest;

            thread1.Start();

            thread2.Start();

            thread3.Start();

            Console.ReadLine();

        }

    }

У нас имеется три потока и три метода, в которых они выполняются. Первый метод выводит на экран числа от 0 до 9, второй — от 10 до 19, третий — с 20 по 29.

В методе Main мы задаём приоритеты потокам. Так как нам надо сначала вывести числа из первого потока, мы устанавливаем ему самый высокий приоритет. Следующий за ним второй поток имеет приоритет чуть ниже, поэтому будет выполняться вторым, третий поток имеет самый низкий приоритет, поэтому будет выполняться после всех остальных приоритетов.

Далее мы запускаем все три потока и смотрим, что же у нас получается:

Потоки в C# для начинающих: разбор, реализация, примеры

Вот и всё! Наши числа вывелись в правильном порядке, и всё благодаря приоритетам.

Также можно поиграться с изменением значения приоритетов потоков. Так, например, можно поменять приоритеты на такие:

thread1.Priority = ThreadPriority.Lowest;

thread2.Priority = ThreadPriority.BelowNormal;

thread3.Priority = ThreadPriority.Highest;

И тогда мы увидим в консоли вот такой вывод:

Потоки в C# для начинающих: разбор, реализация, примеры

Поэкспериментировать с приоритетами можно на примере нашей программы, скачав её по ссылке ниже.

Скачать исходник

Программа №3: типы потоков в C#

Как мы рассказывали выше, потоки в C# бывают приоритетными и фоновыми. Разница между ними в том, что если основной поток будет завершен, то и вложенные в него фоновые потоки также будут завершены принудительно. Если же фоновый поток завершится раньше основного, то на основной поток это не повлияет, и он продолжит свою работу.

Мы также описывали выше, как поменять тип потока в программе, как как по умолчанию все потоки создаются приоритетными. Теперь давайте на практике посмотрим, чем отличаются фоновые потоки в C# от основных.

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

        static void mythread1()

        {

            for (int i = 0; i < 1000000; i++)

            {

                Console.WriteLine(«Поток 1 выводит « + i);

            }

        }

        static void Main(string[] args)

        {

            Thread thread1 = new Thread(mythread1);

            thread1.IsBackground = true;

            thread1.Start();

            Thread.Sleep(100);

        }

    }

Здесь у нас имеется два потока — thread1 и поток в из метода Main. Изначально они являются приоритетными, следовательно, работают независимо друг от друга, и, пока не закончится выполняться один поток, второй поток нельзя будет закончить принудительно. Однако в нашей программе мы присвоили потоку thread1 другой тип — фоновый, в строке:

thread1.IsBackground = true;

А так как данный поток вызывается в методе Main, значит он будет полностью зависеть от потока в этом методе.

Смысл нашей программы в следующем: поток thread1 вызывается из метода Main и начинает работу в методе mythread1, который должен выводить на экран числа от 0 до 999999. Однако загвоздка в том, что практически после старта работа метода Main прекращается (заметьте, у нас нет строки Console.ReadLine(); в конце Main). Поток thread1 никак не успеет вывести все 999999 чисел за столь короткий промежуток времени, но так как в нашей программе он является фоновым, то принудительно завершится вместе с завершением потока в методе Main.

Мы также добавили строку:

Как мы помним, данный метод приостанавливает работу потока на время, указанное скобках (миллисекунды). В нашем случае мы приостанавливаем приоритетный поток исключительно для того, чтобы успеть сделать скриншот вывода (тоже нелегкое дело, успеть сфотографировать экран за одну десятую секунды, но если сделать остановку значительно дольше, то поток thread1 успеет вывести все числа).

Итак, после запуска программы и выжидания 100 мс у нас в консоли следующее:

Потоки в C# для начинающих: разбор, реализация, примеры

Это последние числа, которые успел вывести поток thread1 перед завершением выполнения потока в Main, затем консоль закрывается, и приложение завершает свою работу.

Для дополнительного примера можно убрать или заменить строку thread1.IsBackground = true; (тогда данный поток снова станет приоритетным), удалить Thread.Sleep(100), добавить в конец метода Main строку Console.ReadLine() и снова запустить данную программу. Перед вами начнут проплывать огромное количество чисел, но вы не сможете остановить это действие посредством работы потока в Main (иными словами, нажатием любой кнопки), пока поток thread1 не выполнится полностью и не выведет все 999999 чисел.

Вот в этом и заключается разница между основными и фоновыми потоками в языке C#. Нашу программу (с двумя вариантами выполнения) можно скачать по ссылке ниже, ну а на этом наша статья, посвященная работе потоков в C# заканчивается.

Свои вопросы и пожелания можете оставить в комментариях, спасибо за прочтение!

Скачать исходник

день добрый,

у меня есть некоторый код, в определенном месте которого, я должен ждать пока переменная order_id, не поменяет свое значение. как только данная переменная изменится — двигаемся дальше. для этого я использую таймер. вот код:

 public string order_id = "0"; // переменная для хранения номер выставленной заявки. заявки обрабатываем в очереди, поэтому номер - один. 
       public string order_id_first = "0"; // как, только две этих переменных будут отличаться, значит вышел новый orderid
 
       void smartcom_ordersucceeded(int cookie, string orderid) // событие, если приказ на биржу выставлен успешно
       {
           order_id = orderid;
           logging_trade.log_add(this, "smartcom_ordersucceeded", "одрдер доставлен на сервер котировок. № заявки (cookie): " + cookie + ". № заявки (order_id): " + order_id , 2);
           
       }

public void timer4_Tick(object sender, EventArgs e) // таймер на ожидание прихода номера заявки после place_order
       {
           //logging_trade.log_add(this, "послать задание", "order_id для BUY STOP из таймера: " + order_id, 1);
           //timer4.Enabled = false;
 
           if (order_id != order_id_first) // если они равны, это или 0 = 0, при запуске программы или только что вышел новый orderid
           {
               order_id_first = order_id;
               logging_trade.log_add(this, "таймер 4", "вышел новый orderid. order_id для BUY STOP из таймера: " + order_id, 1);
               timer4.Enabled = false; // остановим таймер.
               new_orderid_flag = true; // флаг перехода к обработке следующей заявки
           }
           else
           {
               logging_trade.log_add(this, "таймер 4", "не новый orderid или первый запуск: " + order_id, 1); 
           }
       } // timer4_Tick
                   timer4.Interval = 50;
                   timer4.Enabled = true;
                   logging_trade.log_add(this, "послать задание", "значение order_id: " + order_id, 4);

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

logging_trade.log_add(this, "послать задание", "значение order_id: " + order_id, 4);

и я в значении order_id я получаю 0.

мне нужно сделать, что бы когда я вызываю таймер, то сначала он отработал — дождался нового значения orderid и после этого программа продолжилась бы выполняться с этого же места, там где я вызывал таймер. подскажите, как быть?

борис

Спросили меня, вроде бы простой вопрос — «Как приостановить выполнение программы на X секунд». Естественно в C#. Первый (и очень часто единственный) вариант это Thread.Sleep(1000); Но для порядка решил погуглить и покопаться на stackoverflow.

И вот к чему я пришел —
Используйте

  1. System.Timers.Timer
  2. System.Windows.Forms.Timer
  3. System.Threading.Timer

Лучше не использовать Thread.Sleep, так как это полностью заблокирует нить и предотвратит её от обработки других сообщений.

Если предположить, что у вас однопоточное приложение (а они большинство), ваше приложение прекратит отвечать на все запросы, а не просто остановится на время, как можно подумать.

Для контроля (сколько времени реально выполнялось) можно использовать System.Diagnostics.Stopwatcth

Пример кода —

using System;
using System.Diagnostics;

namespace TimerTest
{
    class Program
    {
        static System.Timers.Timer aTimer;
        static Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();

        static void Main(string[] args)
        {
            aTimer = new System.Timers.Timer(2000);
            aTimer.Elapsed += OnTimedEvent;
            //Разовое выполнение таймера
            aTimer.AutoReset = false;
            aTimer.Enabled = true;

            Console.WriteLine("Press the Enter key to continue the program at any time... ");
            Console.ReadLine();            

            TimeSpan ts = stopwatch.Elapsed;

            string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                ts.Hours, ts.Minutes, ts.Seconds,
                ts.Milliseconds / 10);
            Console.WriteLine("RunTime " + elapsedTime);
            Console.ReadLine();
        }

        private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
        {
            Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
            stopwatch.Stop();
        }
    }
}

Исправлена

system("read -r -p "Press any key to continue..." key")

Теперь я пишу инструмент командной строки и используя язык C, но мне интересно, как приостановить программу? (Не прервать его, но можно продолжить) Я пытался сделать это так: «Нажмите Enter To Continue».

Я нахожусь в Linux, поэтому у меня нет или что у меня есть, и я попробовал «pause()», но эта функция не может реализовать «Нажмите Enter To Continue», ее нельзя повторить.

Интересно, есть ли функция или что может помочь мне сделать это? Если да, пожалуйста, скажите мне, спасибо!

PS: Это мои коды выше, как вы можете видеть, я использую функцию с именем «conti», чтобы установить паузу

PLUS: Игнорируйте эти функции «задержки», просто выполняя тесты.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void delay500ms(void){
unsigned char i,j,k;
for(i=15;i>0;i--)
for(j=202;j>0;j--)
for(k=81;k>0;k--);
}

void delay1s(void){
unsigned char h,i,j,k;
for(h=5;h>0;h--)
for(i=4;i>0;i--)
for(j=116;j>0;j--)
for(k=214;k>0;k--);
}

int pause(void);

int ldown (int ln)
{
int k;
for (k=0;k<ln;k++)
{
printf("n");
}
}

void conti ()
{
printf("nnPress Enter To Continue...nn");
}

void cmd ()
{
ldown(100);
system("toilet -f mono12 -F metal S-MODE");
ldown(4);
printf("[1] Emergency Rebootn");
printf("[2] Clean All Progressn");
printf("[3] Change Into Pure Netn");
printf("[4] Change Into Normal Netn");
printf("[5] Edit This Scriptn");
printf("[6] Rebuild This Scriptn");
printf("[7] Delet This Scriptn");
printf("[8] Exit S-MODEnn");
printf("Now Please Type Your Command [1~8]:n");
int cmdn;
cmdn = 8;
scanf("%d",&cmdn);
ldown(4);
switch (cmdn)
{
case 1:
printf("Checking Root Permision...nn");
system("reboot");
printf("nnShutting Down The System...nn");
conti();
break;
case 2:
printf("Cleaning All Progress...nn");
system("kill -9 -1");
conti();
break;
case 3:
system("pure");
conti();
break;
case 4:
system("unpure");
conti();
break;
case 5:
printf("Checking Root Permision...nn");
system("sudo vim /bin/engage.c");
break;
case 6:
printf("Checking Root Permision...nn");
system("sudo gcc /bin/engage.c -o /bin/engage");
printf("nnScript Rebuilt! Please Restart The Scriptn");
conti();
break;
case 7:
printf("Checking Root Permision...nn");
system("sudo rm /bin/engage");
exit(0);
break;
case 8:
printf("Exiting...");
ldown(10);
exit(0);
break;
default:
printf("Unknow Command :(nn");
break;
}
}

void main()
{
do
{
cmd();
} while (1==1);
}

Понравилась статья? Поделить с друзьями:
  • Как приостановить работу ростелекома на время
  • Как проверить бизнес идею на жизнеспособность
  • Как проверить время работы компьютера за день
  • Как проверить время работы телевизора lg oled
  • Как проверить время работы телевизора philips