Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Corrupted memory with Hello World with Pthreads

I'm working through some simple pthread examples form llnl.computing.gov pthreads tutorial. The program on the website prints out the address of the threadid, but I would like to pass the address of the id to PrintHello, and then use dereference the address to get the id. I think with the sleep in there every thread should print 8 (the number of threads). The code is

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NUM_THREADS  8

void *PrintHello(void *threadid)
{
   long *taskid = (long *)threadid;
   sleep(1);
   printf("Hello from thread %ld\n", *taskid);
   pthread_exit(NULL);
} 

int main(int argc, char *argv[])
{
  pthread_t threads[NUM_THREADS];
  int rc;
  long t;

  for(t=0;t<NUM_THREADS;t++) {
    printf("Creating thread %ld\n", t);
    rc = pthread_create(&threads[t], NULL, PrintHello, (void *) &t);
    if (rc) {
      printf("ERROR; return code from pthread_create() is %d\n", rc);
      exit(-1);
    }
 }
 pthread_exit(NULL);
}

When I compile and run this in Cygwin it seg faults with stack corruption errors. If I rewrite PrintHello as:

void *PrintHello(void *threadid)
{
  long taskid = (long) threadid;
  sleep(1);
  printf("Hello from thread %ld\n", taskid);
  pthread_exit(NULL);
 }

it doesn't seg fault, it just prints the address and I would like to dereference the address and get the value of t from main.

Does anyone have some pointers on how to accomplish that goal? I know I can pass t to pthread_create instead of &t but I want to do it this way for learning purposes.

like image 936
CallMeNorm Avatar asked Dec 12 '22 23:12

CallMeNorm


2 Answers

When you call pthread_exit(NULL) from the main thread, it terminates that thread. At that point, any local variables in the main function, including t, are destroyed and can no longer be used.

If the main thread exits before all of your worker threads are finished using t (via the pointer you pass to them via pthread_create), your program exhibits undefined behavior.

The program contains a race condition because the access of the variable t from the worker threads and the destruction of the variable t from the main thread are unsynchronized. One way to fix this problem would be to have the main thread join with each of the worker threads (via pthread_join) before it exits.

like image 187
James McNellis Avatar answered Dec 14 '22 13:12

James McNellis


1) you pass the address of t so every thread will get a pointer to the same variable, that's not the thread ID, it's a long which has a value that keeps changing. You are modifying the variable in main and reading it in each other thread, which is a data race.

2) Probably what happens is that by the time the new threads execute the loop in main has finished and the variable has gone out of scope. When main exits its local variables will be popped off the stack, so when the other threads access t it is no longer on the stack. You don't have any synchronisation in your program to prevent that, so you have another data race there. You need to wait in main for the threads to finish, which you can do by calling pthread_join to wait for each one, but that still won't change the fact the other threads are trying to read a variable while it's being written to by another thread.

3) There's no need to call pthread_exit there, returning from the function or from main automatically exits the thread (just like calling exit(0) causes main() to finish)

like image 33
Jonathan Wakely Avatar answered Dec 14 '22 13:12

Jonathan Wakely