Как реализовать приоритетное упреждающее планирование (аналогично прерываниям) с потоками в C++

Я хочу написать программу на C++ для Windows (но желательно с поддержкой кроссплатформенности), в которой у меня есть два потока, запланированных на основе упреждающее планирование с приоритетом, которое похоже на поведение прерывания (когда прерывание происходит, основной поток приостанавливается, где бы он ни находился, и только когда поток прерывания снова переходит в спящий режим, основной поток возобновляется с того места, где он был приостановлен).

Это темы:

  1. Тема T_main
  2. Поток T_interrupt.

T_main все время работает в цикле while. Предполагается, что T_interrupt выполняется раз в секунду и делает что-то очень быстро.

Код в T_main довольно большой (тысячи строк кода).

Это должно быть очень точное время.

Я хочу, чтобы, когда придет время для запуска потока T_interrupt, ему был присвоен приоритет, чтобы он работал без перерыва, пока не завершится, и только тогда поток T_main возобновится с того места, где он остановился.

Если вам интересно, что я пытаюсь сделать, то вот основное объяснение: По сути, я запускаю симуляцию своего встроенного проекта. Я издевался над всем своим оборудованием и хочу запустить свое приложение на симуляторе на ПК. Цель состоит в том, чтобы проверить логическую реализацию моего приложения. Принимаются во внимание различия компиляторов и другие несовершенства. Для меня критически важно иметь возможность имитировать прерывание на основе 1-секундного таймера, которое существует на моем MCU. Мне трудно имитировать такое поведение, поскольку планирование потоков кажется совместным, а не упреждающим.

Я пытался использовать приоритеты и устанавливать методы планирования, такие как Round Robin SCHED_RR или FIFO SCHED_FIFO, но во всех случаях реализация планирования по-прежнему является кооперативной, а не упреждающей.

Вот мой код:

#include <iostream>
#include <thread>
#include <pthread.h>
#include <string>

using namespace std;

void MainApplicationFunc(void)
{
    // Infinite loop in which the app is running
    while(1)
    {
        MainProgram();
    }
}

void TickTimerInterruptFunc()
{
    while(1)
    {
        TickTimer();
        std::this_thread::sleep_for(1s);
    }
}

void setScheduling(std::thread &th, int policy, int priority)
{
    sched_param sch_params;
    sch_params.sched_priority = priority;
    if(pthread_setschedparam(th.native_handle(), policy, &sch_params))
    {
        std::cerr << "Failed to set Thread scheduling" << std::endl;
    }
}

int main()
{
    std::thread T_interrupt(TickTimerInterruptFunc);
    setScheduling(T_interrupt, SCHED_FIFO, 1);
    std::thread T_main(MainApplicationFunc);
    setScheduling(T_main, SCHED_FIFO, 20);

    T_main.join();
    T_interrupt.join();
}

person Eyal Gerber    schedule 08.02.2021    source источник
comment
IMHO T_main будет работать до тех пор, пока он не будет заблокирован вводом-выводом или блокировкой вручную, и не будет прерван T_interrupt, потому что оба являются SCHED_FIFO, а T_main имеет более высокий приоритет, чем T_interrupt.   -  person t.niese    schedule 08.02.2021
comment
stackoverflow.com/questions/63442172/ В этом вопросе могут быть некоторые идеи, с которыми вы можете работать.   -  person ttemple    schedule 09.02.2021
comment
@t.niese - значение более низкого приоритета преобразуется в поток с более высоким приоритетом, поэтому на самом деле T_interrupt запланирован с более высоким приоритетом, чем T_main.   -  person Eyal Gerber    schedule 10.02.2021


Ответы (1)


Я нашел несколько решений этой проблемы и решил поделиться ими со всеми остальными. На протяжении stackoverflow я нашел других, которые задавали подобные вопросы, и есть несколько возможных решений.

Возможные решения для реализации поведения прерывания с потоками:

  1. Принудительно переключите контекст в потоке. Я нашел полезную ссылку на то, как это сделать в Windows, как показано в Симулятор FreeRTOS Windows. Лично для меня это лучший вариант. Более того, я мог бы просто использовать этот симулятор вместо того, чтобы создавать свой собственный.
  2. Напишите драйвер Windows, как указано здесь: https://stackoverflow.com/a/13819216/4441211
  3. Используйте SuspendThread и ResumeThread. Хотя при использовании этого метода вы должны знать, что они асинхронны по своей природе, как показано здесь так что это не идеально.
person Eyal Gerber    schedule 11.02.2021