Как сделать секундомер на c

Обновлено: 04.07.2024

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

Подключим заголовочные файлы:

. отличием нашей функции (путь это будет how2timer) является то, что она принимает значение времени в миллисекундах ;)

Для всех делов мы воспользуемся функцией clock(), которая возвращает время, измеряемое процессором в тактах от начала выполнения программы, или ?1, если оно не известно. Проверок делать не будем) не до того нам =)

Также оприделена константа CLOCKS_PER_SEC - это количество тактов системных часов в секунду.
Нам естественно необходимо пересчитать это время для работы с миллисекундами.
Когда константа готова сосчитаем время завершения отсчёта.

Мне нужно было реализовать класс секундомера, который будет использоваться для измерения времени выполнения различных функций другими. Окончательное время работы должно быть напечатано в формате 9h 3min 2s 23s 32ms 87us 78ns. Если большие единицы равны нулю, они должны быть опущены. Длительность времени в определенном временном модуле, таком как секунды или миллисекунды, может быть получена из функций, аналогичных hours . Мне нужны лучшие идеи для улучшения реализации.

Мне нужно руководствоваться тем, как сделать это более эффективно, поскольку мой код уже слишком запутанный :( У меня также есть следующие вопросы:

  1. Есть ли способ генерировать функции в течение часов, секунд и т. д. динамически?
  2. Как я могу улучшить функцию operator ? Есть ли способ иметь список единиц времени, которые я могу повторить?

1 ответ

Разное:.

Улучшения кода - класс:

Используйте typedefs для уменьшения дублирования кода (и если вам когда-либо понадобится изменить тип часов, это намного проще). Они должны быть общедоступными.

Сохраните тип продолжительности при разрешении часов, вместо использования duration .

Функция часов должна быть const, но я бы рекомендовал заменить ее функцией, которая возвращает время в наиболее точных единицах. Класс секундомера не должен беспокоиться о конверсиях во времени - только код пользователя знает нужную точность и может duration_cast при необходимости:

Так как код утверждает в рабочем состоянии в start() и stop() , нам, вероятно, нужна функция, чтобы проверить, работает ли секундомер:

Улучшения кода - вывод:

Теперь, когда у нас есть get_elapsed_time() , оператору ostream не нужно быть другом.

Используйте auto здесь.

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

Оператор ostream должен взять секундомер по команде const & amp ;, а не по значению. (Я сомневаюсь, что это имеет большое значение с точки зрения производительности, но это делает намерение и семантику более ясными - конечно, нам не нужно копировать объект секундомера для печати времени?). Аутсорсинг печати для отдельной функции также делает вещи немного опрятными (больше строк кода, но меньше дублирования). Это может быть функция лямбда, если вы хотите.

Было бы чище не давать stop_watch оператора ostream вообще. Если вы создаете код print_time_to_stream(stream, time) , который занимает время как std::chrono::nanoseconds (или что-то самое высокое разрешение, которое вам нужно в вашем приложении), тогда ваша функция печати может использоваться в любое время, а не только для stop_watch class!

Ваши вопросы

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

Так как std::chrono::hours и т. д. являются типами, их нельзя просто добавить к вектору. Я полагаю, вы могли бы сделать что-то вроде:

Итак, вектор times содержит время для использования в единицах stop_watch::duration_t . И затем вы можете использовать целочисленное деление для получения необходимых значений вместо duration_cast ing.

Другие вещи

Если вы просто измеряете время работы, вам может не понадобиться логика запуска /остановки. Вы могли бы упростить класс следующим образом:

Содержание:

Шаг 1

Откроем Visual Studio и создадим приложение Windows Forms.

Шаг 2

Добавим в форму два элемента управления Button и назовем их Start и Stop , хотя имена вы можете написать любые, по своему усмотрению. Окончательная форма выглядит следующим образом:

Шаг 3

Теперь давайте добавим в нашу программу элемент управления Timer . Перетащим его из Visual Studio Toolbox в форму. С помощью такой нехитрой манипуляции в нашей форме появится элемент – timer1 .

Шаг 4

1 секунда = 1000 миллисекунд.

Шаг 5

Теперь нужно нажать кнопку Events и добавить обработчик событий Timer , дважды щелкнув по свойству Tick . Событие таймера здесь — timer1_Tick (как показано на изображении ниже).

Шаг 6

Теперь добавим классы FileStream и StreamWriter в начало нашей программы. Они используются для создания нового текстового файла и реализации записи данных в него. Все классы определены в библиотеке базовых классов System.IO , поэтому обязательно импортируйте System.IO в начале программы.

Мы видим из предыдущего участка кода, что класс FileStream создает файл mcb.txt на диске C , а StreamWriter определен для записи в него данных. Теперь напишем алгоритм реализации записи нескольких строк в наш файл:

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

Остался последний шаг — создать событие timer1_Tick , записывающее текущую дату в текстовый файл:

Шаг 7

Мы только что разобрали, как использовать таймер в начале разработки приложения с помощью визуального конструктора Visual Studio. Но иногда вам может потребоваться программно использовать таймер во время выполнения этого приложения.

Например: создадим такой таймер, установим ему необходимые свойства, а также добавим обработчик событий, интервал сделаем равным 2 секундам:

Допустим, мы хотим отобразить текст в элементе управления ListBox . Следующий код добавляет текст и обновляет ListBox каждые 2 секунды:

Класс Timer также можно использовать, если вы хотите вызывать событие через заданный промежуток времени:

Событие в предыдущем примере будет запускаться каждые 5 секунд.

Резюме

Закрепить приведенный материал можно на базе таких видео:

Понадобилось мне реализовать на современном С++ таймер, да не простой… В статье разобраны несколько вариантов таймера (от простого к интересному).

Простейший таймер на C++

Итак, самый простой таймер должен подождать заданное время, а потом вызвать нужную нам функцию. При этом возможны два варианта: приостановиться может основной поток или задержка и вызов функции могут быть вынесены в отдельный поток. Реализация:

Если требуется асинхронное выполнение — создается новый объект потока и для него вызывается метод detach() , за счет этого поток работает независимо от основного потока. Функция std::this_thread::sleep_for останавливает поток на заданное время (в нашем случае задается в миллисекундах), после задержки вызывается наша callback-функция.

В функции main в таймер добавляются три функции. Первой добавляется bar , однако у этой функции задана большая задержка, чем у foo — поэтому выполнится она позже. Третья функция добавляется асинхронной чтобы затормозить основной поток до тех пор, пока не завершат выполнение два других потока.


Результат работы программы:

Обратите внимание, что функция add таймера принимает на вход функцию типа void(void) . Я не стал заморачиваться с шаблонами, т.к. если вам понадобится добавить функцию другого типа или даже вызов функции класса — вы всегда можете поместить туда лямбда-функцию, выполняющую нужный вызов.

Более сложный таймер

Теперь нам точно нужен класс:

  • m_is_running хранит состояние таймера — true если в таймер добавлена функция, которую надо выполнить (она еще не была выполнена);
  • m_delay хранит задержку выполнения текущей функции;
  • m_start хранит время, когда в таймер была добавлена последняя функция;
  • m_callback — последняя добавленная в таймер функция;
  • все описанные выше параметры являются общими для главного потока и потока, замеряющего время — обращения к ним должна быть защищены мьютексом m_changing_mutex .

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

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

В этом коде я предлагаю обратить внимание на работу с мьютексом (для тех, кто раньше на работал с std::lock_guard ) — это выглядит так здорово потому, что реализована идиома RAII (этот же принцип заложен в умные указатели типа unique_ptr). Так, функция add блокирует мьютекс создавая объект std::lock_guard , при этом объект создается на стеке, т.е. при выходе из функции (в том числе при возникновении исключения) ресурс освобождается. Аналогичным образом ресурс захватывается начиная с создания объекта std::lock_guard до конца итерации во вспомогательном потоке, замеряющем время.

Про замер времени можно прочитать в статье «Замерить время работы функции на С++«.

Читайте также: