Boost - выполнение периодических задач с использованием boost::thread

Boost, threads, chrono

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

Например, программа запускается и делает 10 отсчётов в течение 10 секунд, при этом программа будет выводить информацию о номере отсчёта в консоль.

Работа программы будет выглядеть следующим образом.

Выполнение периодический задачи в консольном приложении

Структура проекта

Проект использует систему сборки CMake, поэтому структура проекта будет следующей.

Структура проекта PeriodicTask

CMakeLists.txt

Здесь находится стандартный конфиг CMake для сборки проекта

cmake_minimum_required (VERSION 3.8)

project(Periodic)

set(CMAKE_CXX_STANDARD 17)
set(Boost_USE_STATIC_LIBS ON)

find_package(Boost 1.68 REQUIRED COMPONENTS thread)

set(SOURCE_FILES
        Periodic/main.cpp
        Periodic/PeriodicTask.cpp)

SET(HEADER_FILES
        Periodic/PeriodicTask.h)

if(Boost_FOUND)
    include_directories(${Boost_INCLUDE_DIRS})
    add_executable(Periodic ${SOURCE_FILES} ${HEADER_FILES})
    target_link_libraries(Periodic ${Boost_LIBRARIES})
endif()

PeriodicTask.h

Заголовочный файл периодической задачи.

В самом простом случае для создания класса периодической задачи нам потребуются:

  • указание периода срабатывания
  • объект std::function для хранения задачи
  • переменная bool для остановки и запуска задачи. В данном примере останавливать задачу не будем, но если добавить методы run/stop, то вполне можно это реализовать
  • boost::thread - поток, без которого подобный функционал не реализовать
#pragma once

#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <functional>
#include <atomic>

class PeriodicTask
{
public:
    explicit PeriodicTask(const boost::chrono::milliseconds &period, const std::function<void()> &func);

    virtual ~PeriodicTask();

private:
    boost::chrono::milliseconds m_period;   // Период срабатывания задачи
    std::function<void()> m_func;           // Функция, которая будет выполнять периодическую задачу
    std::atomic<bool> m_running;            // Переменная, которая указывает, что выполнение задачи запушено, с помощью неё можно в дальнейшем останавливать задачу
    boost::thread m_thread;                 // Поток для выполнения задачи
};

PeriodicTask.cpp

#include "PeriodicTask.h"

PeriodicTask::PeriodicTask(const boost::chrono::milliseconds &period, const std::function<void()> &func) :
    m_period(period),
    m_func(func),
    m_running(true)
{
    // Создаём объект потока для выполнения периодической задачи
    m_thread = boost::thread([this]
    {
        while (m_running)
        {
            // Для выполнения задачи с определённым периодом погружаем поток в сон после каждого выполнения задачи
            boost::this_thread::sleep_for(m_period);
            if (m_running)
            {
                // выполняем задачу
                m_func();
            }
        }
    });
}

PeriodicTask::~PeriodicTask()
{
    // При уничтожении объекта с периодической задачей
    m_running = false;
    // прерываем поток, иначе программа не освободит ресурсы системы, пока поток не выйдет из сна
    // это критично, если период срабатывания задачи измеряется десятками секунд и больше
    m_thread.interrupt();
    m_thread.join();
}

main.cpp

Файл с функцией main. Когда мы создаём объект периодической задачи, то мы помещаем в качестве задачи в него лямбда функцию, как наиболее простой способ указания, какую работу требуется выполнить.

#include "PeriodicTask.h" // Подключим заголовочный файл класса для выполнения периодических задач

#include <iostream>

int main(int argc, const char* argv[])
{
    std::cout << "Start program" << std::endl;
    int count = 0;
    // Создадим периодическую задачу с периодом 1 секунда
    PeriodicTask p(boost::chrono::seconds{ 1 }, [&count]() {
        // Выводим счётчик и увеличиваем его на единицу
        std::cout << count++ << std::endl;
    });

    // Остановим основной поток программы на 10 секунд, чтобы 10 раз успела отработать периодическая задача
    boost::this_thread::sleep_for(boost::chrono::seconds{ 10 });
    std::cout << "End program" << std::endl;
    return 0;
}

Заключение

В качестве заключения прилагаю архив с проектом.

Periodic.zip Periodic.zip

Виртуальный хостинг со скидкой 10 процентов
Виртуальный хостинг со скидкой 10 процентов
EVILEG предлагает надёжный хостинг со скидкой 10% на виртуальный хостинг и 5% на VPS
Поддержать автора Donate

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
G
24 июля 2019 г. 4:20
G0tzef

C++ - Тест 005. Структуры и Классы

  • Результат:66баллов,
  • Очки рейтинга-1
VK
24 июля 2019 г. 3:49
Viktoriia Komarova

C++ - Тест 001. Первая программа и типы данных

  • Результат:40баллов,
  • Очки рейтинга-8
G
24 июля 2019 г. 3:25
G0tzef

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80баллов,
  • Очки рейтинга4
Последние комментарии
23 июля 2019 г. 12:14
IscanderChe

Вот ссылка: https://github.com/iscander-che/TestReportViewer .
23 июля 2019 г. 5:42
Евгений Легоцкой

Хорошо, хотя конечно это С, а не С++ )))) Но если вдруг будут проблемы, то решение через класс со статическими переменными вы видели ))
23 июля 2019 г. 5:33
IscanderChe

"Не потребует каждый раз объявлять extern в других файлах". И так не требует. У меня в тестовом классе эти переменные используются без дополнительного объявления. Так же объявил их в cpp-файле о…
23 июля 2019 г. 5:28
IscanderChe

В репозиторий могу сегодня вечером выложить. "Или ее надо компилить самому под дистриб?" Тут я не совсем понимаю, что вы имеете ввиду. Я выложу в репозиторий исходный код утилиты, и всё.
23 июля 2019 г. 4:32
Евгений Легоцкой

Есть комментарий по вашему коду. Лучше бы вместо глобальных переменных в стиле Си, то есть с использоавнием extern, написали бы статические переменные в рамках класса. IMHO - это будет выглядеть…
Сейчас обсуждают на форуме
24 июля 2019 г. 4:57
Михаиллл

Это не помогает. Ниже мой код Rectangle{ //Flickable { //contentX: 100 id: rectangleForListView y: parent.height * 0.15 height: parent.height * 0.…
24 июля 2019 г. 3:17
Евгений Легоцкой

Ну вот теперь я несколько в ступоре. Запустите из консоли проект и посмотрите тогда, на что ругается. Также, следовало бы посмотреть в настройках самой виртуальной машины, что по поддержке OpenG…
23 июля 2019 г. 8:20
Михаиллл

Так работает QFile f1(dbAdress); f1.setPermissions(QFileDevice::WriteOther);
23 июля 2019 г. 7:11
Pavel K.

Советую использовать нечто такое или такое
22 июля 2019 г. 10:50
Pavel K.

Благодарю.Буду пробовать.
Ищу работу?
5,000.00 руб. - 15,000.00 руб.
Дизайнер
Moskovskiy, Moscow, Russia
25,000.00 руб. - 30,000.00 руб.
Разработчик Qt/C++
Barnaul, Altai Krai, Russia

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

EVILEG
О нас
Услуги
Присоединяйтесь к нам
© EVILEG 2015-2019
Рекомендует хостинг TIMEWEB