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

Рейтинг: 0Ответов: 0Опубликовано: 26.02.2023

Есть такая функция, вызывается она в отдельном потоке Pthread

#include "otca.h"

//Подключение логики систем
//MAIN PANEL
#include "avionics/main_panel.h"
//TIME LOGIC
#include "avionics/time_logic.h"

//Переменные потоков систем
//TIME LOGIC
pthread_t time_logic_thread;
//MAIN PANEL
//acs
pthread_t main_panel_acs_thread;

void * OTCA_CORE_SIM(void * opaque){
    PROP_CYCLE CYCLE;
    pthread_mutex_init(&CYCLE.cycle_mutex, NULL);
    pthread_cond_init(&CYCLE.cycle_condition, NULL);
    OTCA_CORE_STRUCT *OTCA_CORE_DATA = (OTCA_CORE_STRUCT*)opaque;

    //запуск систем
    //TIME LOGIC
    pthread_create(&time_logic_thread, NULL, time_logic_update, (void *) &CYCLE);
    //MAIN PANEL
    //acs
    pthread_create(&main_panel_acs_thread, NULL, main_panel_acs_update, (void *) &CYCLE);

    CYCLE.all_operations = 2;

    while (OTCA_INIT_SIM_RUN == 1) {
        //Подготовка отсчета времени цикла
        clock_t  cycle_start = clock();

        CYCLE.current_opperation = 0;

        fprintf(stdout, "### Sim Cycle Started ###\n\n");

        //Выдача разрешений на выполнение
        //TIME LOGIC
        time_logic_run();
        time_logic_passed(); //Функция ожидающая прохождения time_logic
        //MAIN PANEL
        //acs
        main_panel_acs_run();
        

        //Ожидание завершения симуляции
        //OTCA_SYSTEM_WAIT();
        while (1) {
            //pthread_mutex_lock(&CYCLE.cycle_mutex);
            //pthread_cond_wait(&CYCLE.cycle_condition, &CYCLE.cycle_mutex);
            fprintf(stdout, "-- Here I am and %d\n", CYCLE.current_opperation);
            //pthread_mutex_unlock(&CYCLE.cycle_mutex);
            break;
        }

        //Подсчет времени обработки симуляции
        OTCA_CORE_DATA->cycle_time = (double)(clock() - cycle_start) / CLOCKS_PER_SEC;

        //Ожидание конца симуляции
        Sleep((uint32_t)((OTCA_INIT_SIM_PERIOD - OTCA_CORE_DATA->cycle_time) * 1000));
        fprintf(stdout, "\n### Sim Cycle Passed ###\n\n");

    }

    //Выгрузка потоков систем
    //TIME LOGIC
    pthread_detach(time_logic_thread);
    //MAIN PANEL
    //acs
    pthread_detach(main_panel_acs_thread);

    pthread_cond_destroy(&CYCLE.cycle_condition);
    pthread_mutex_destroy(&CYCLE.cycle_mutex);

    return NULL;
}

Логика работы следующая, данный поток запускает отдельные потоки систем, вот пример функции потока системы:

#include <semaphore.h>

#include "otca/properties.h"
#include "otca/functions.h"

#include "time_logic.h"

//time_logic
sem_t time_logic_work; //разрешающий семафор
sem_t time_logic_wait; //блокирующий семафор
void time_logic_run() {
    sem_post(&time_logic_work);
}
void * time_logic_update(void * opaque) {
    PROP_CYCLE *CYCLE = (PROP_CYCLE*)opaque;
    sem_init(&time_logic_work, 0, 0);
    sem_init(&time_logic_wait, 0, 0);

    double time_last = SIM_TIME.total_running_time_sec; // time for previous frame
    double last_m = FLIGHTMODEL_POSITION.M;

    while (OTCA_INIT_SIM_RUN) {
        sem_wait(&time_logic_work);

        //time calculations
        double time_now = SIM_TIME.total_running_time_sec;
            double passed = fabs(time_now - time_last);
            double curent_m = FLIGHTMODEL_POSITION.M;
            //print(passed)
            if (curent_m - last_m == 0) {
                passed = 0;
            }
            if (passed > 0.1) {
                passed = 0.1;
            }

            //TIME.frame_time = passed;

            //last variables
            time_last = time_now;
            //last_m = curent_m

        fprintf(stdout, "Time logic Passed\n");
        pthread_mutex_lock(&CYCLE->cycle_mutex);
        CYCLE->current_opperation = CYCLE->current_opperation + 1;
        fprintf(stdout, "Time logic data = %d\n",CYCLE->current_opperation);
        if (CYCLE->current_opperation == CYCLE->all_operations) {
            pthread_cond_broadcast(&CYCLE->cycle_condition);
        }
        pthread_mutex_unlock(&CYCLE->cycle_mutex);
        sem_post(&time_logic_wait);
    }
    sem_destroy(&time_logic_work);
    sem_destroy(&time_logic_wait);
    return NULL;
}
void time_logic_passed() {
    sem_wait(&time_logic_wait);
}
#include <semaphore.h>

#include "otca/properties.h"
#include "otca/functions.h"

#include "main_panel.h"

//acs
sem_t main_panel_acs_work; //разрешающий семафор
sem_t main_panel_acs_wait; //блокирующий семафор
void main_panel_acs_run() {
     sem_post(&main_panel_acs_work);
}
void * main_panel_acs_update(void * opaque) {
    PROP_CYCLE *CYCLE = (PROP_CYCLE*)opaque;
    sem_init(&main_panel_acs_work, 0, 0);
    sem_init(&main_panel_acs_wait, 0, 0);

    uint8_t sec_mode[] = {0, 0, 0}; // chrono mode. 0 - reset, 1 - run, 2 - hold

    double chrono_sec_angle[] = {0, 0, 0}; // chrono sec needle
    double chrono_min_angle[] = {0, 0, 0}; // chrono min needle
    double sec_time[] = {0, 0, 0}; // chrono counter
    double start_sec[] = {0, 0, 0}; //time, when chrono started

    //flight timer variables
    double flight_mode[] = {0, 0, 0};
    double flight_time[] = {0, 0, 0};
    double flight_hour_angle[] = {0, 0, 0};
    double flight_min_angle[] = {0, 0, 0};
    double start_flight[] = {0, 0, 0};

    uint8_t knob_last = 0;

    while (OTCA_INIT_SIM_RUN) {
        sem_wait(&main_panel_acs_work);

        double knob_summ = GAUGES_ACS[0].left_knob_press + GAUGES_ACS[0].right_knob_press + GAUGES_ACS[1].left_knob_press + GAUGES_ACS[1].right_knob_press + GAUGES_ACS[2].left_knob_press + GAUGES_ACS[2].right_knob_press;
        //do nothing if buttons released
        if (knob_summ == 0) {
                knob_last = 0;
        } else if (knob_summ != knob_last) {
            //playSample(btn_click, 0) //SOUND
            knob_last = knob_summ;
            //set clock modes
            double sim_time = SIM_TIME.total_running_time_sec;  // take actual sim time in seconds
            if (GAUGES_ACS[0].left_knob_press == 1) {
                flight_mode[0] = flight_mode[0] + 1;
                if  (flight_mode[0] > 2) {
                    flight_mode[0] = 0;
                }
                start_flight[0] = sim_time;
            } else if (GAUGES_ACS[0].right_knob_press == 1) {
                sec_mode[0] = sec_mode[0] + 1;
                if (sec_mode[0] > 2) {
                    sec_mode[0] = 0;
                }
                start_sec[0] = sim_time;
            } else if (GAUGES_ACS[1].left_knob_press == 1) {
                flight_mode[1] = flight_mode[1] + 1;
                if (flight_mode[1] > 2) {
                    flight_mode[1] = 0;
                }
                start_flight[1] = sim_time;
            } else if (GAUGES_ACS[1].right_knob_press == 1) {
                sec_mode[1] = sec_mode[1] + 1;
                if (sec_mode[1] > 2) {
                    sec_mode[1] = 0;
                }
                start_sec[1] = sim_time;
            } else if (GAUGES_ACS[2].left_knob_press == 1) {
                flight_mode[2] = flight_mode[2] + 1;
                if (flight_mode[2] > 2) {
                    flight_mode[2] = 0;
                }
                start_flight[2] = sim_time;
            } else if (GAUGES_ACS[2].right_knob_press == 1) {
                sec_mode[2] = sec_mode[2] + 1;
                if (sec_mode[2] > 2) {
                    sec_mode[2] = 0;
                }
                start_sec[1] = sim_time;
            }
        }

        double sim_time = SIM_TIME.total_running_time_sec; // take actual sim time in seconds
        double main_time = SIM_TIME.zulu_time_sec;  // take actual UTC time
        uint8_t fail_enabled = FAILURES.failures_enabled;
        uint8_t fail_1 = FAILURES.acs_fail[0];
        uint8_t fail_2 = FAILURES.acs_fail[1];
        uint8_t fail_3 = FAILURES.acs_fail[2];

        //set main time angles
        double main_sec_angle = main_time * 360 / 60;
        double main_min_angle = main_sec_angle / 60;
        double main_hour_angle = main_min_angle / 12;

        if (fail_enabled * fail_1 == 0) {
            GAUGES_ACS[0].needle_hours = main_hour_angle;
        }
        if (fail_enabled * fail_2 == 0) {
            GAUGES_ACS[1].needle_hours = main_hour_angle;
        }
        if (fail_enabled * fail_3 == 0) {
            GAUGES_ACS[2].needle_hours = main_hour_angle;
        }
        if (fail_enabled * fail_1 == 0) {
            GAUGES_ACS[0].needle_mins = main_min_angle;
        }
        if (fail_enabled * fail_2 == 0) {
            GAUGES_ACS[1].needle_mins = main_min_angle;
        }
        if (fail_enabled * fail_3 == 0) {
            GAUGES_ACS[2].needle_mins = main_min_angle;
        }

        // set chronometer angles 1
        if (sec_mode[0] == 0) {
            sec_time[0]= 0;
            chrono_min_angle[0] = sec_time[0];
            chrono_sec_angle[0] = sec_time[0];
        } else if (sec_mode[0] == 1) {
            sec_time[0] = sim_time - start_sec[0];
            sec_time[0] = floor(sec_time[0] * 5) / 5;
            chrono_min_angle[0] = sec_time[0] * 360 / (60 * 60);
            chrono_sec_angle[0] = chrono_min_angle[0] * 60;
        } else {
            chrono_min_angle[0] = sec_time[0] * 360 / (60 * 60);
            chrono_sec_angle[0] = chrono_min_angle[0] * 60;
        }
        if (fail_enabled * fail_1 == 0) {
            GAUGES_ACS[0].needle_secs = chrono_sec_angle[0];
            GAUGES_ACS[0].stopwatch_mins = chrono_min_angle[0];
        }

        // set chronometer angles 2
        if (sec_mode[1] == 0) {
            sec_time[1]= 0;
            chrono_min_angle[1] = sec_time[1];
            chrono_sec_angle[1] = sec_time[1];
        } else if (sec_mode[1] == 1) {
            sec_time[1] = sim_time - start_sec[1];
            sec_time[1] = floor(sec_time[1] * 5) / 5;
            chrono_min_angle[1] = sec_time[1] * 360 / (60 * 60);
            chrono_sec_angle[1] = chrono_min_angle[1] * 60;
        } else {
            chrono_min_angle[1] = sec_time[1] * 360 / (60 * 60);
            chrono_sec_angle[1] = chrono_min_angle[1] * 60;
        }
        if (fail_enabled * fail_2 == 0) {
            GAUGES_ACS[1].needle_secs = chrono_sec_angle[1];
            GAUGES_ACS[1].stopwatch_mins = chrono_min_angle[1];
        }

        // set chronometer angles 3
        if (sec_mode[2] == 0) {
            sec_time[2]= 0;
            chrono_min_angle[2] = sec_time[2];
            chrono_sec_angle[2] = sec_time[2];
        } else if (sec_mode[2] == 1) {
            sec_time[2] = sim_time - start_sec[2];
            sec_time[2] = floor(sec_time[2] * 5) / 5;
            chrono_min_angle[2] = sec_time[2] * 360 / (60 * 60);
            chrono_sec_angle[2] = chrono_min_angle[2] * 60;
        } else {
            chrono_min_angle[2] = sec_time[2] * 360 / (60 * 60);
            chrono_sec_angle[2] = chrono_min_angle[2] * 60;
        }
        if (fail_enabled * fail_3 == 0) {
            GAUGES_ACS[2].needle_secs = chrono_sec_angle[2];
            GAUGES_ACS[2].stopwatch_mins = chrono_min_angle[2];
        }

        // set flight timer angles 1
        if (flight_mode[0] == 0) {
            flight_time[0] = 0;
            flight_hour_angle[0] = flight_time[0];
            flight_min_angle[0] = flight_time[0];
            GAUGES_ACS[0].flag_pos = -1;
        } else if (flight_mode[0] == 1) {
            flight_time[0] = sim_time - start_flight[0];
            flight_hour_angle[0] = flight_time[0] * 360 / (60 * 60 * 12);
            flight_min_angle[0] = flight_hour_angle[0] * 12;
            GAUGES_ACS[0].flag_pos = 1;
        } else {
            flight_hour_angle[0] = flight_time[0] * 360 / (60 * 60 * 12);
            flight_min_angle[0] = flight_hour_angle[0] * 12;
            GAUGES_ACS[0].flag_pos = 0;
        }
        if (fail_enabled * fail_1 == 0) {
            GAUGES_ACS[0].flight_timer_mins = flight_min_angle[0];
            GAUGES_ACS[0].flight_timer_hours = flight_hour_angle[0];
        }

        // set flight timer angles 2
        if (flight_mode[1] == 0) {
            flight_time[1] = 0;
            flight_hour_angle[1] = flight_time[1];
            flight_min_angle[1] = flight_time[1];
            GAUGES_ACS[1].flag_pos = -1;
        } else if (flight_mode[1] == 1) {
            flight_time[1] = sim_time - start_flight[1];
            flight_hour_angle[1] = flight_time[1] * 360 / (60 * 60 * 12);
            flight_min_angle[1] = flight_hour_angle[1] * 12;
            GAUGES_ACS[1].flag_pos = 1;
        } else {
            flight_hour_angle[1] = flight_time[1] * 360 / (60 * 60 * 12);
            flight_min_angle[1] = flight_hour_angle[1] * 12;
            GAUGES_ACS[1].flag_pos = 0;
        }
        if (fail_enabled * fail_2 == 0) {
            GAUGES_ACS[1].flight_timer_mins = flight_min_angle[1];
            GAUGES_ACS[1].flight_timer_hours = flight_hour_angle[1];
        }

        // set flight timer angles 3
        if (flight_mode[2] == 0) {
            flight_time[2] = 0;
            flight_hour_angle[2] = flight_time[2];
            flight_min_angle[2] = flight_time[2];
            GAUGES_ACS[2].flag_pos = -1;
        } else if (flight_mode[2] == 1) {
            flight_time[2] = sim_time - start_flight[2];
            flight_hour_angle[2] = flight_time[2] * 360 / (60 * 60 * 12);
            flight_min_angle[2] = flight_hour_angle[2] * 12;
            GAUGES_ACS[2].flag_pos = 1;
        } else {
            flight_hour_angle[2] = flight_time[2] * 360 / (60 * 60 * 12);
            flight_min_angle[2] = flight_hour_angle[2] * 12;
            GAUGES_ACS[2].flag_pos = 0;
        }
        if (fail_enabled * fail_3 == 0) {
            GAUGES_ACS[2].flight_timer_mins = flight_min_angle[2];
            GAUGES_ACS[2].flight_timer_hours = flight_hour_angle[2];
        }

        fprintf(stdout, "ACS Logic Passed\n");
        //pthread_mutex_lock(&CYCLE->cycle_mutex);
        CYCLE->current_opperation = CYCLE->current_opperation + 1;
        fprintf(stdout, "ACS data = %d\n",CYCLE->current_opperation);
        if (CYCLE->current_opperation == CYCLE->all_operations) {
            fprintf(stdout, "HAPPY WORK = %d\n",CYCLE->current_opperation);
            pthread_cond_broadcast(&CYCLE->cycle_condition);
        }
        //pthread_mutex_unlock(&CYCLE->cycle_mutex);
        sem_post(&main_panel_acs_wait);
    }
    sem_destroy(&main_panel_acs_wait);
    sem_destroy(&main_panel_acs_work);
    return NULL;
}
void main_panel_acs_passed() {
    sem_wait(&main_panel_acs_wait);
}

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

Тип PROP_CYCLE:

//служебная структура
    typedef struct PROP_CYCLE {
        int current_opperation;
        int all_operations;
        pthread_mutex_t cycle_mutex;
        pthread_cond_t cycle_condition;
    } PROP_CYCLE;

Я закомментировала в core ожидание условное племенной и представленный код выдает такой вывод:

### Sim Cycle Started ###

Time logic Passed
Time logic data = 1
-- Here I am and 1
ACS Logic Passed
ACS data = 2
HAPPY WORK = 2

### Sim Cycle Passed ###

Естественно в таком варианте он работает бесконечно.

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

Ответы

Ответов пока нет.