title: c thread concurrency and memory mix up
body: <p>I have a multithread program in C. there is only 1 thread function (thread_read_file), that will read a file content into a variable from a struct.
  this function has an automatic variable thiscontent, in which the content of the file should be stored using fread.</p>
  
  <p>the main program is executing 4 threads to read 4 different files at regular interval to update the content into memory.</p>
  
  <p>no matter what I tried, I get the result followed by some garbage after some time.
  I tried forcing adding a '\0' after my reading, but no, it would display the garbage anyhow.</p>
  
  <p>here is the code:</p>
  
  <pre><code>#include &lt;stdlib.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;time.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;pthread.h&gt;
  #include &lt;string.h&gt;
  
  #define WAIT_TIME 2
  
  /* change_it:
   * 8: picture for texture 0 finished to load into ram, needs to be set to 2 afterwards
   * 7: picture for texture 0 loading
   * 6: picture for texture 1 finished to load into ram, needs to be set to 2 afterwards
   * 5: picture for texture 1 loading
   * 4: pre stage 1, initialize time variable for time constant blending
   * 3: initial -&gt; allows initial loading of textures
   * 2: texture has finished changed, dont change it anymore
   * 1: initiate texture change
   * 0: don't change any texture */
  int change_it = 0;
  signed int offset = -1;
  int check_id = WAIT_TIME*100+1;
  
  typedef struct {
      pthread_mutex_t read_mutex; // synchronize access to reading flag
      int reading;                                // 0 = not reading , 1 = reading , 2 = finished reading
      char *content;                          // content of file
      char *file;                              // file to read
  } struct_file_content;
  
  struct_file_content struct_data_file[4];
  
  char *file_content[4];
  
  // temperature in abu dhabi
  #define file1 "/home/tias/repository/data/temp_ad.txt"
  
  // temperature in irsch
  #define file2 "/home/tias/repository/data/temp_ir.txt"
  
  // change EUR / AED
  #define file3 "/home/tias/repository/data/change.txt"
  
  // monitoring data used to color cubes
  #define file4 "/home/tias/repository/data/summary.txt"
  
  void change_or_not(signed int* offset, int* check_id, int* change_it) {
  
      if ( *offset == -1 ) {
          *offset = (signed int) ( time(NULL) ) % WAIT_TIME;
      }
  
      int delta       = (int) ( ( ( (long) time(NULL) ) - *offset ) % WAIT_TIME );
      int delta_id = (int) ( (long) time(NULL) % (WAIT_TIME * 100) );
  
      if ( *check_id &gt; WAIT_TIME*100 ) *check_id  = delta_id;
  
      if ( delta == 0 &amp;&amp; *check_id != delta_id &amp;&amp; *change_it == 0 ) {
          //*change_it = 4;
          *change_it = 1;
          *check_id   = delta_id;
      }
  
      if ( delta == 0 &amp;&amp; *check_id != delta_id &amp;&amp; *change_it == 2 ) *change_it = 0;
  
  }
  
  void pretend_texture_blending ( int* change_it ) {
      static old_change_it = 0;
      static int ori = 0;
      if ( old_change_it == 0 &amp;&amp; *change_it == 1 ) {
          ori = time(NULL);
      }
      if ( time(NULL) &gt; ori &amp;&amp; *change_it == 1 ) {
          ori = time(NULL);
          *change_it = 2;
      }
      old_change_it = *change_it;
  }
  
  void *thread_read_file(void *data) {
  
      struct_file_content *thisdata = data;
      int mutex_res;
      long length;
      char *thiscontent = NULL;
  
      // lock mutex
      mutex_res = pthread_mutex_lock(&amp;thisdata-&gt;read_mutex);
  
      if (mutex_res != 0) {
          fprintf(stderr, "thread_read_file() failed to acquire mutex: %s\n", strerror(mutex_res));
          pthread_exit(NULL);
      } else {
          fprintf(stdout, "thread_read_file: mutex locked for file: %s\n",thisdata-&gt;file);
      }
      // end locking procedure
  
      // let's open the file now
      FILE *f = fopen(thisdata-&gt;file, "r");
  
      // let's get the size of the file and bounce if it is too large
      // if size is acceptable, read the file into memory
      if (f) {
          fseek(f, 0, SEEK_END);
          length = ftell(f);
          fseek (f, 0, SEEK_SET);
  
          if (length &gt; 39) {
              fprintf(stderr, "file %s is too big\n", thisdata-&gt;file);
              pthread_exit(NULL);
          }
  
          thiscontent = (char*)malloc((length+1)*sizeof(char));
  
          if (thiscontent) {
              fread(thiscontent, 1, length, f);
          } else {
              perror("malloc(3) error");
              pthread_exit(NULL);
          }
  
          fclose(f);
  
          // puzzling result is here :
          // first run with the 4 threads always work fine
          // next runs will randomly display mixed values / other memory locations
  
          fprintf(stdout,"thiscontent: %s length was %d for file %s\n",thiscontent,length,thisdata-&gt;file);
  
      } else {
          fprintf(stderr, "cannot open file %s\n", thisdata-&gt;file);
          pthread_exit(NULL);
      }
      // file read and fd closed
  
      // free old allocation of this content
      free(thisdata-&gt;content);
      thisdata-&gt;reading = 2;
      // assign new result to newly freed char*
      thisdata-&gt;content = thiscontent;
  
      // unlock mutex as everything has been updated
  
      mutex_res = pthread_mutex_unlock(&amp;thisdata-&gt;read_mutex);
  
      if (mutex_res != 0) {
          fprintf(stderr, "thread_read_file() failed to release mutex: %s\n", strerror(mutex_res));
          pthread_exit(NULL);
      } else {
          fprintf(stdout,"thread_read_file: mutex unlocked for file: %s\n", thisdata-&gt;file);
      }
      // end unlock mutex procedure
  
      return NULL;
  }
  
  int main(int argc, char** argv) {
  
      static int init = 1;
  
      int p,q,r,curtime;
      float X,Y;
      static int data_update_done[4] = { 0,0,0,0 };
  
      static pthread_t thread_file[4];
      static int thread_res[4] = { 0,0,0,0 };
  
      static char *files[4];
      files[0] = (char*)malloc(sizeof(char)*strlen(file1));
      files[1] = (char*)malloc(sizeof(char)*strlen(file2));
      files[2] = (char*)malloc(sizeof(char)*strlen(file3));
      files[3] = (char*)malloc(sizeof(char)*strlen(file4));
  
      int mutex_err[4];
  
      // init = 1
      // =&gt; launches the 4 threads for reading the 4 files
      // 
      if ( init == 1 ) {
  
          strcpy(files[0],file1);
          strcpy(files[1],file2);
          strcpy(files[2],file3);
          strcpy(files[3],file4);
  
          for ( p = 0 ; p &lt; 4 ; p++ ) {
  
              mutex_err[p] = pthread_mutex_init(&amp;struct_data_file[p].read_mutex, NULL);
  
              if (mutex_err[p] != 0 ) {
                  fprintf(stderr, "pthread_mutex_init(3) error: %s\n", strerror(mutex_err[p]));
                  exit(EXIT_FAILURE);
              }
  
              struct_data_file[p].reading = 1;
              struct_data_file[p].content = NULL;
              struct_data_file[p].file = files[p];
  
              thread_res[p] = pthread_create(&amp;thread_file[p], NULL, thread_read_file, &amp;struct_data_file[p]);
  
          }
  
      init = 0;
  
      }
  
      // main loop
      while (1) {
  
          change_or_not(&amp;offset, &amp;check_id, &amp;change_it);
          usleep(50000);
          fprintf(stdout,".%u.",change_it);
          fflush(stdout);
          pretend_texture_blending(&amp;change_it);
  
          for ( p = 0 ; p &lt; 4 ; p++ ) { // updating data if ready, destroying mutex when done, etc...
  
              // lock mutex
              mutex_err[p] = pthread_mutex_lock(&amp;struct_data_file[p].read_mutex);
  
              if ( mutex_err[p] != 0 ) {  
                  fprintf(stderr, "pthread_mutex_lock(3) error: %s\n",strerror(mutex_err[p]));
                  exit(EXIT_FAILURE);
              }
              // end lock mutex
  
              // data update routine
              // is data ready: check variable 'reading' from the struct_data_file struct
              // 2            -&gt; yes : update + destroy mutex 
              // 1 or 0 -&gt; no : unlock mutex
  
              if ( struct_data_file[p].reading == 2 ) { // data is ready
                  if (file_content[p]) free(file_content[p]);
                  file_content[p] = (char *)malloc(strlen(struct_data_file[p].content)*sizeof(char));
                  strcpy(file_content[p],struct_data_file[p].content);
                  struct_data_file[p].reading = 0;
                  mutex_err[p] = pthread_mutex_unlock(&amp;struct_data_file[p].read_mutex);
                  if (mutex_err[p] != 0) {
                      fprintf(stderr, "Warning: Error destroying mutex: %s\n", strerror(mutex_err[p]));
                  }
              } else {
                  mutex_err[p] = pthread_mutex_unlock(&amp;struct_data_file[p].read_mutex);
                  if ( mutex_err[p] != 0 ) {
                      fprintf(stderr, "pthread_mutex_unlock(3) error: %s\n",strerror(mutex_err[p]));
                      exit(EXIT_FAILURE);
                  }
              }
              // end checking if data is ready
          }
  
          if ( change_it == 1 ) {
              for ( p = 0 ; p &lt; 4 ; p++ ) {
                  if ( struct_data_file[p].reading == 0 ) {
                      if ( data_update_done[p] == 0 ) {
                          thread_res[p] = pthread_create(&amp;thread_file[p], NULL, thread_read_file, &amp;struct_data_file[p]);
                          data_update_done[p] = 1;
                      }
                  }
              }
          }
  
          if ( change_it == 2 ) {
              for ( p = 0 ; p &lt; 4 ; p++ ) {
                  data_update_done[p] = 0;
              }
          }
  
      // end main loop
      }
  // end main
  }
  </code></pre>
  
  <p>the output is</p>
  
  <pre><code>thiscontent: abu dhabi:35.6 length was 14 for file /home/tias/repository/data/temp_ad.txt
  thread_read_file: mutex unlocked for file: /home/tias/repository/data/temp_ad.txt
  thread_read_file: mutex locked for file: /home/tias/repository/data/summary.txt
  thiscontent: AED/euro:4.09534 length was 16 for file /home/tias/repository/data/change.txt
  thiscontent: 11111 length was 5 for file /home/tias/repository/data/summary.txt
  thread_read_file: mutex unlocked for file: /home/tias/repository/data/summary.txt
  thread_read_file: mutex unlocked for file: /home/tias/repository/data/change.txt
  .1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..0..1.thread_read_file: mutex locked for file: /home/tias/repository/data/temp_ir.txt
  thread_read_file: mutex locked for file: /home/tias/repository/data/temp_ad.txt
  thread_read_file: mutex locked for file: /home/tias/repository/data/summary.txt
  thread_read_file: mutex locked for file: /home/tias/repository/data/change.txt
  thiscontent: AED/euro:4.09534 length was 16 for file /home/tias/repository/data/change.txt
  thread_read_file: mutex unlocked for file: /home/tias/repository/data/change.txt
  thiscontent: abu dhabi:35.6 length was 14 for file /home/tias/repository/data/temp_ad.txt
  thread_read_file: mutex unlocked for file: /home/tias/repository/data/temp_ad.txt
  thiscontent: irsch:14.6.09534 length was 10 for file /home/tias/repository/data/temp_ir.txt
  thread_read_file: mutex unlocked for file: /home/tias/repository/data/temp_ir.txt
  thiscontent: 1111 length was 5 for file /home/tias/repository/data/summary.txt
  thread_read_file: mutex unlocked for file: /home/tias/repository/data/summary.txt
  .1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..0..1.thread_read_file: mutex locked for file: /home/tias/repository/data/temp_ad.txt
  thread_read_file: mutex locked for file: /home/tias/repository/data/temp_ir.txt
  thread_read_file: mutex locked for file: /home/tias/repository/data/summary.txt  
  thread_read_file: mutex locked for file: /home/tias/repository/data/change.txt
  thiscontent: irsch:14.6.09534 length was 10 for file /home/tias/repository/data/temp_ir.txt
  thread_read_file: mutex unlocked for file: /home/tias/repository/data/temp_ir.txt
  thiscontent: abu dhabi:35.6 length was 14 for file /home/tias/repository/data/temp_ad.txt
  thread_read_file: mutex unlocked for file: /home/tias/repository/data/temp_ad.txt
  thiscontent: AED/euro:4.09534 length was 16 for file /home/tias/repository/data/change.txt
  thread_read_file: mutex unlocked for file: /home/tias/repository/data/change.txt
  thiscontent: 1111 length was 5 for file /home/tias/repository/data/summary.txt
  thread_read_file: mutex unlocked for file: /home/tias/repository/data/summary.txt
  </code></pre>
  
  <p>the 4 files have constant content.</p>
  
  <p>the first 4 results are always correct (4 threads reading the 4 files, first set of results is always correct for as far as I saw and I have done so many tests).</p>
  
  <p>however when the variable thiscontent is displayed (after the first run), I get additional output or even less output (with the file summary.txt that contains 11111)</p>
  
  <p>for instance:
  I got thiscontent: irsch:14.6.09534
  I should have got thiscontent: irsch:14.6</p>
  
  <p>Also
  I should get all the time:
  thiscontent: 11111 length was 5
  but sometimes I get 
  thiscontent: 1111 length was 5</p>
  
  <p>I do not understand why and cannot fix it.
  I am puzzled by the fact that the variable thiscontent is automatic, and thus should get initialized at every function call.
  however output reveals different.</p>
  
  <p>it might be a memory allocation issue but I have no idea at the moment.</p>
  
  <p>any help greatly appreciated.</p>
  
  <p>PS: you might find some piece of useless code, this is because the main program is an opengl screensaver that I wrote, and is 1000 lines long.</p>
  
  <p>the code I have posted is an extract from this screensaver, reproducing the issue, but without tons of useless code for this very troubleshooting.</p>
  
  <p>thank you</p>
  
  <p>PS no2: you can copy/paste this code into a file called threads.c and compile it using:</p>
  
  <pre><code>gcc -o threads threads.c -lpthread -D_REENTRANT
  </code></pre>