Search code examples
cprintfpthreads

Why is fprintf not working as intended in my code?


I have a function that calculates some estimates and prints them out into a file. This program is called in multiple threads to do calculations for different initial conditions. Each thread creates separate files to write the values so there is no file conflict involved. The values are printed in scientific notation. My Problem is that while printing, even though most of the values are printed properly some are (one or two) printed missing the 'e' in the exponential part having some -ve signs, or generally breaking formatting. While this doesn't seem major, it breaks the rest of the pipeline since, the programs that use these files as input fail to parse it properly. The barebone code is given below. The loop that calls the function.

The loop which calls the function.

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);
    }

This passes the initial conditions to a function which combines the arguments and passes to the function which calcualtes the values.

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);}

I have removed the codes which initialize the system since it is not relevant to the question. The Kalman function takes in the struct {kf} and updates the values in it. The fprintf commands in the loop are supposed to print the lines to files. The kf struct is defined like

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;

I tried using different formatting styles (le instead of e) but it didn't change anything. The fact these errors appear completely random in completely random files doesn't help either.

The normal output looks like this

-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
........................
........................

But some of the bad output values looks like this

-3.0.049398e-13
1.-12
- -1.922051e-13

I searched around online but couldnt find anyone mentioning similar issues and I hope someone can shed some light in this.


Solution

  • You need to refresh your knowledge about scope and lifetime of variables.

    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);
            
        }
    

    In this code, you only have 1 array args at any given time and after the loop is left, the variable is no longer valid at all. That means, if one of the threads is executed while you are still in the loop (which is not ensured) it will only see what was stored there last. If the thread is executed after the loop was already left, the memory is no longer valid and reading the content is causing undefined behaviour.

    You must use static memory. Either define a variable with static lifetime or use dynamic memory allocation:

    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);
        }
    

    Maybe your printout already shows where you are wrong:

    printf("thread no %d ran \n",i);
    

    When you reach that line, the thread was created and can be executed. It does not mean at all that it got any CPU cycle so far or even finished its task.