tags:

views:

51

answers:

4

So here's my scenario. First, I have a structure -

struct interval
{
    double lower; 
    double higher;
}

Now my thread function -

void* thread_function(void* i)
{
    interval* in = (interval*)i; 
    double a = in->lower; 
    cout << a; 
    pthread_exit(NULL)
}

In main, let's say I create these 2 threads -

pthread_t one,two; 
interval i; 

i.lower = 0; i.higher = 5; 
pthread_create(&one,NULL,thread_function,&i);

i.lower=10; i.higher = 20; 
pthread_create(&two,NULL,thread_function, &i); 

pthread_join(one,NULL);
pthread_join(two,NULL);

Here's the problem. Ideally, thread "one" should print out 0 and thread "two" should print out 10. However, this doesn't happen. Occasionally, I end up getting two 10s.

Is this by design? In other words, by the time the thread is created, the value in i.lower has been changed already in main, therefore both threads end up using the same value?

+3  A: 

Is this by design?

Yes. It's unspecified when exactly the threads start and when they will access that value. You need to give each one of them their own copy of the data.

sbi
+3  A: 

Your application is non-deterministic.
There is no telling when a thread will be scheduled to run.

Note: By creating a thread does not mean it will start executing immediately (or even first). The second thread created may actually start running before the first (it is all dependant on the OS and hardware).

To get deterministic behavior each thread must be given its own data (that is not modified by the main thread).

pthread_t one,two; 
interval oneData,twoData 

oneData.lower = 0; oneData.higher = 5; 
pthread_create(&one,NULL,thread_function,&oneData);

twoData.lower=10; twoData.higher = 20; 
pthread_create(&two,NULL,thread_function, &twoData); 

pthread_join(one,NULL);
pthread_join(two,NULL);

I would not call it by design.
I would rather refer to it as a side-effect of scheduling policy. But the observed behavior is what I would expect.

Martin York
+1  A: 

This is the classic 'race condition'; where the results vary depending on which thread wins the 'race'. You have no way of knowing which thread will 'win' each time.

Andrew Barber
+1  A: 

Your analysis of the problem is correct; you simply don't have any guarantees that the first thread created will be able to read i.lower before the data is changed on the next line of your main function. This is in some sense the heart of why it can be hard to think about multithreaded programming at first.

The straight forward solution to your immediate problem is to keep different intervals with different data, and pass a separate one to each thread, i.e.

interval i, j;
i.lower = 0; j.lower = 10;
pthread_create(&one,NULL,thread_function,&i);
pthread_create(&two,NULL,thread_function,&j);

This will of course solve your immediate problem. But soon you'll probably wonder what to do if you want multiple threads actually using the same data. What if thread 1 wants to make changes to i and thread 2 wants to take these into account? It would hardly be much point in doing multithreaded programming if each thread would have to keep its memory separate from the others (well, leaving message passing out of the picture for now). Enter mutex locks! I thought I'd give you a heads up that you'll want to look into this topic sooner rather than later, as it'll also help you understand the basics of threads in general and the required change in mentality that goes along with multithreaded programming.

I seem to recall that this is a decent short introduction to pthreads, including getting started with understanding locking etc.

gspr