Rückfrage zu Thread Verhalten



  • Einen wunderbaren Heiligabend zusammen,

    ich habe eine Frage zu folgendem Snippet:
    (Herkunft: https://randu.org/tutorials/threads/)

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    /* To see, wether Threads are waiting independently */
    #include <time.h>
    
    #define NUM_THREADS 5
    
    /* create thread argument struct for thr_func() */
    typedef struct _thread_data_t {
      int tid;
      int delay;
      double stuff;
    } thread_data_t;
    
    /* shared data between threads */
    double shared_x;
    pthread_mutex_t lock_x;
    
    void *thr_func( void *arg ) {
      thread_data_t *data = (thread_data_t *)arg;
      /*Wait a bit, before we continue, just to destroy the continuous flow!*/
      struct timespec t_delay, t_rem = { 0 };
      int rc = 0;
      rc = nanosleep( &t_delay, &t_rem );
      if( rc )
      {
        printf( "Could not use nanosleep properly\n" );
      }
      t_delay.tv_sec = data->delay;
      printf("hello from thr_func, thread id: %d\n", data->tid);
      /* get mutex before modifying and printing shared_x */
      pthread_mutex_lock( &lock_x );
        shared_x += data->stuff;
        printf("x = %f\n", shared_x);
      pthread_mutex_unlock( &lock_x );
    
      pthread_exit(NULL);
    }
    
    int main( int argc, char **argv ) {
      srand( time( NULL ) );
      pthread_t thr[NUM_THREADS];
      int i, rc;
      /* create a thread_data_t argument array */
      thread_data_t thr_data[NUM_THREADS];
    
      /* initialize shared data */
      shared_x = 0;
    
      /* initialize pthread mutex protecting "shared_x" */
      pthread_mutex_init( &lock_x, NULL );
    
      /* create threads */
      for (i = 0; i < NUM_THREADS; ++i) {
        thr_data[i].tid = i;
        thr_data[i].stuff = (i + 1) * NUM_THREADS;
        thr_data[i].delay = 1 + rand()/((RAND_MAX + 1u) / 10 );
        if ( ( rc = pthread_create( &thr[i], NULL, thr_func, &thr_data[i] ) ) ) {
          fprintf(stderr, "error: pthread_create, rc: %d\n", rc);
          return EXIT_FAILURE;
        }
      }
      /* block until all threads complete */
      for ( i = 0; i < NUM_THREADS; ++i ) {
        pthread_join( thr[i], NULL );
      }
    
      return EXIT_SUCCESS;
    }
    
    

    Der Vorgang mit den Locks erschließt sich mir, zumindest dachte ich das. Aber unter manchen Umständen erhalte ich eine Ausgabe die ich mir nicht ganz erklären kann.

    hello from thr_func, thread id: 0
    hello from thr_func, thread id: 2
    hello from thr_func, thread id: 1
    hello from thr_func, thread id: 4
    hello from thr_func, thread id: 3
    x = 5.000000
    x = 20.000000
    x = 30.000000
    x = 55.000000
    x = 75.000000
    
    

    Das die Reihenfolge sich verändert verstehe ich, das war ja meine Intention um das Konzept zu begreifen. Jedoch kann ich mir nicht erklären, weshalb die Ausgabe auf diese Art und Weise manchmal "sortiert" wird.

    In Einzelfällen hätte ich gesagt, es liegt am Lock, dass dieser angefordert wird und dies führt zu einer verzögerten Ausgabe / Erhöhung des Wertes. Aber diese saubere Ausgabe getrennt nach zwei Sätzen in derselben Funktion verstehe ich nicht ganz.

    Könnt Ihr mir einen kleinen Denkschubser geben, wieso sich das Snippet so verhält?

    Danke im Voraus und besinnlichen Heiligabend.



  • Dieser Beitrag wurde gelöscht!


  • @fairiestoy
    Probier mal t_delay zu initialisieren, z.B. mit einem Zufallszahlengenerator. Vielleicht bekommst du dann ein besser durcheinandergewürfeltes Ergebnis.

    Ansonsten... ja, ist schon etwas komisch. Aber kann halt passieren. printf ist halt IO, d.h. es kann sein dass der Thread an der Stelle kurz schlafen gelegt wird. Wenn alle Threads quasi gleichzeitig loslaufen und gleich lange im nanosleep schlafen, dann kann halt das was du da beobachtest dabei rauskommen.



  • @hustbaer
    Ach Mensch, ich habe übersehen, dass ich beim verschieben des Codeteils für t_delay, die Wertzuweisung nicht mit übernommen habe. t_delay wurde hier erst nach dem sleep gesetzt.

    Ich habe den Code korrigiert und jetzt tauchte das Verhalten auch nicht mehr auf, zumindest in den letzten 10 Läufen nicht mehr.

    Danke für den Schubser ^^



  • @fairiestoy sagte in Rückfrage zu Thread Verhalten:

    t_delay wurde hier erst nach dem sleep gesetzt.

    Ah, stimmt, die Zeile hab ich ganz übersehen. Bzw. einfach nicht mehr soweit gelesen, weil davor ja schon was faul war 🙂

    Danke für den Schubser ^^

    Bitte 🙂