Search code examples
clinuxmultithreadingpthreadsstdio

Pthread Programming Short Example


I am having some trouble understanding this code since I am new to pthread programming. From what I understand, we create N threads and execute the run function on them, which only prints the thread number. Am I missing something?

Is there any advantage of using snprintf (with buffers) over printf in this particular case? Could this program be improved any further?

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

static int N = 5;
static void* run(void *arg)
{
    int *i = (int *) arg;
    char buf[123];
    snprintf(buf, sizeof(buf), "thread %d", *i);
    return buf;
}

int main(int argc, char *argv[])
{
   int i;
   pthread_t *pt = NULL;
   for (i = 0; i < N; i++) {
       pthread_create(pt, NULL, run, &i);
   }

   return EXIT_SUCCESS;
}

Solution

  • First of all, your threads return garbage. Deferencing the pointer returned would be Undefined Behaviour because it points to storage that no longer exists after the function returns. Good thing nothing used the pointer.

    Next, the threads don't print anything because snprintf outputs to an array, not stdout.

    Furthermore, the threads would print garbage if you switched to printf because the same pointer is passed to to all threads.

    And that's assuming the threads have a chance to run since main doesn't wait for the threads to finish. You gotta join them.

    Fixed:

    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #define N 5
    
    static void *run(void *arg) {
        size_t job = *(size_t*)arg;
        printf("Job %zu\n", job);
        return NULL;
    }
    
    int main(int argc, char *argv[]) {
       size_t jobs[N];
       pthread_t threads[N];
       for (size_t i=0; i<N; ++i) {
           jobs[i] = i;
           pthread_create(threads+i, NULL, run, jobs+i);
       }
    
       for (size_t i=0; i<N; ++i) {
           pthread_join(threads[i], NULL);
       }
    
       return EXIT_SUCCESS;
    }
    

    It's also common to pass an integer cast to a pointer.

    #include <inttypes.h>
    #include <pthread.h>
    #include <stdio.h>
    #include <stdint.h>
    
    #define N 5
    
    static void *run(void *arg) {
        uintptr_t job = (uintptr_t)arg;
        printf("Job %" PRIuPTR "\n", job);
        return NULL;
    }
    
    int main(int argc, char *argv[]) {
       pthread_t threads[N];
       for (uintptr_t i=0; i<N; ++i) {
           pthread_create(threads+i, NULL, run, (void*)i);
       }
    
       for (uintptr_t i=0; i<N; ++i) {
           pthread_join(threads[i], NULL);
       }
    
       return EXIT_SUCCESS;
    }