У меня есть функция, которая вычисляет некоторые оценки и распечатывает их в файл. Эта программа вызывается в нескольких потоках для выполнения вычислений для различных начальных условий. Каждый поток создает отдельные файлы для записи значений, чтобы не возникало конфликта файлов. Значения печатаются в экспоненциальном формате. Моя проблема заключается в том, что во время печати, хотя большинство значений печатаются правильно, некоторые (одно или два) печатаются без буквы «e» в экспоненциальной части, имеют некоторые знаки -ve или вообще нарушают форматирование. Хотя это не кажется серьезным, оно нарушает остальную часть конвейера, поскольку программы, использующие эти файлы в качестве входных данных, не могут правильно их проанализировать. Базовый код приведен ниже. Цикл, вызывающий функцию.
Цикл, вызывающий функцию.
for (int i = 0; i < 12; i++) {
void* args[2] = {clock_pairs[i], Q_matrices[i]};
pthread_create(&K_threads[i], NULL, calculate_kalman, (void*)args);
printf("thread no %d ran \n",i);
}
for (int i = 0; i < 12; i++) {
pthread_join(K_threads[i], NULL);
}
При этом начальные условия передаются в функцию, которая объединяет аргументы и передается в функцию, которая вычисляет значения.
void Calculate_Kalman(const char *filename, const char *filename1, double** processNoise)
{
char kalman_filename[256];
sprintf(kalman_filename, "K_%s_%s", filename, filename1);
FILE *kalman_file = fopen(kalman_filename, "w");
if (!kalman_file)
{
perror("Error opening file for writing");
exit(EXIT_FAILURE);
}
char Error_filename[256];
sprintf(Error_filename, "E_%s_%s", filename, filename1);
FILE *E_file = fopen(Error_filename, "w");
if (!E_file)
{
perror("Error opening file for writing");
exit(EXIT_FAILURE);
}
for (int i = 0; i < SampleSize; i++)
{
kf.z = diff[i] + normalRandom(0,pow(measurementNoise,0.5));
Kalman(&kf); // Kalman function call.
// Print the current state estimate
fprintf(kalman_file, "%e, %e\n", gsl_matrix_get(kf.x, 0, 0), gsl_matrix_get(kf.x, 1, 0));
fprintf(E_file, "%e,%e\n", gsl_matrix_get(kf.S, 0, 0), gsl_matrix_get(kf.S, 1, 0));
// Add kf.S values to the dynamic matrix
double row[NUM_VARS] = {gsl_matrix_get(kf.S, 0, 0), gsl_matrix_get(kf.S, 1, 0)};
addRow(&matrix, row);
}
fclose(kalman_file);}
Я удалил коды, инициализирующие систему, поскольку это не имеет отношения к вопросу. Функция Калмана принимает структуру {kf} и обновляет в ней значения. Команды fprintf в цикле должны печатать строки в файлы. Структура kf определяется как
typedef struct
{
gsl_matrix *x; // State estimate (3x1 matrix)
gsl_matrix *P; // Error covariance (3x3 matrix)
gsl_matrix *Q; // Process noise covariance (3x3 matrix)
double R; // Measurement noise covariance (scalar)
gsl_matrix *K; // Kalman gain (3x1 matrix)
gsl_matrix *Phi; // State transition matrix (3x3 matrix)
gsl_matrix *S; // Noise vector (3x1 matrix)
gsl_matrix *H;
double z;
} KalmanFilter;
Я пробовал использовать разные стили форматирования (le вместо e), но это ничего не изменило. Тот факт, что эти ошибки появляются совершенно случайно в совершенно случайных файлах, также не помогает.
Обычный вывод выглядит так
-3.257449e-15, -1.437916e-18
8.742356e-11, 5.662028e-14
-1.929949e-10, -1.779626e-13
1.927338e-10, 2.305067e-13
-8.744399e-11, -1.284666e-13
........................
........................
Но некоторые из плохих выходных значений выглядят так
-3.0.049398e-13
1.-12
- -1.922051e-13
Я поискал в Интернете, но не нашел никого, кто бы упоминал подобные проблемы, и я надеюсь, что кто-нибудь сможет пролить свет на этот вопрос.
pthread_create(&K_threads[i], NULL, calculate_kalman, (void*)args);
Это вызывает неопределенное поведение. args
перестанет существовать, когда вы покинете этот цикл for
. Вы передаете адрес этого массива только своим потокам, но после этого память больше не действительна. И если случится так, что некоторые потоки будут выполнены до того, как вы выйдете из цикла, все они увидят одни и те же значения.
Создайте структуру для передачи нескольких аргументов функции потока. Затем либо создайте массив этой структуры, по одному элементу для каждого потока, либо создайте структуру динамически для каждого потока».
Что такое calculate_kalman
? Связано ли Calculate_Kalman
? Я считаю, что смешивать верхний и нижний регистр — плохая идея.
Вам необходимо освежить свои знания об области действия и времени жизни переменных.
for (int i = 0; i < 12; i++) {
void* args[2] = {clock_pairs[i], Q_matrices[i]};
pthread_create(&K_threads[i], NULL, calculate_kalman, (void*)args);
printf("thread no %d ran \n",i);
}
В этом коде у вас есть только один массив args
в любой момент времени, и после выхода из цикла переменная вообще больше не действительна.
Это означает, что если один из потоков выполняется, пока вы все еще находитесь в цикле (что не гарантировано), он увидит только то, что было сохранено там последним.
Если поток выполняется после выхода из цикла, память больше недействительна, и чтение содержимого вызывает неопределенное поведение.
Вы должны использовать статическую память. Либо определите переменную со статическим временем жизни, либо используйте динамическое распределение памяти:
void* args[12][2];
for (int i = 0; i < 12; i++) {
args[i][0] = clock_pairs[i];
args[i][1] = Q_matrices[i];
pthread_create(&K_threads[i], NULL, calculate_kalman, (void*)args[i]);
printf("thread no %d ran \n",i);
}
Возможно, ваша распечатка уже показывает, в чем вы ошибаетесь:
printf("thread no %d ran \n",i);
Когда вы достигнете этой строки, поток будет создан и может быть выполнен. Это вовсе не означает, что он уже получил какой-либо цикл процессора или даже выполнил свою задачу.
Им не обязательно требуется статическая или выделенная продолжительность хранения для решения поднятой вами проблемы. Им просто нужно гарантировать, что время жизни args
не закончится до того, как потоки перестанут обращаться к его элементам. Это все еще можно сделать с помощью автоматического или продолжительного хранения потоков в таком случае, когда к ним присоединяется та же функция, которая создает потоки.
Что такое
calculate_kalman
? Потенциально вы передаете одни и те же параметры (void* args[2] ...
) всем вызовам этой функции.