Ожидание завершения обработки алгоритмов в потоках с помощью условных переменных
Есть такая функция, вызывается она в отдельном потоке 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 ожидал выполнение симуляций во всех потоках и таким образом записывал время обработки
Источник: Stack Overflow на русском