views:

88

answers:

5

We have the following line of code:

printf("%d\n", toc->runlist.next);
printf("%d\n", toc->runlist.next);

These are the definitions:

typedef struct thread_overview_control{
    int id[NR_UTHREADS];
    list_t runlist;
    int active_counter;
    int main_thread;
    int need_resched;
} thread_overview_control;

thread_overview_control* toc;

What I'm trying to do is implement user threads. For some reason the output of the above code at the point where our test run crushes is:

12345678  //some address
0         //NOW IT'S NULL?!?!?!

How can this happen?? All we do is read a variable. And the strange thing is, without printf's there are no crashes. What's going on?

+3  A: 

Most likely another thread is accessing (and changing) the variable between your two calls to printf(). If you remove the printf statements the timing changes and the behaviour is different.

If the data is indeed being accessed by multiple threads, you need to protect it with a mutex.

Vicky
But if the two `printf`s are really one after the other, the probability of this happening is rather low...
leonbloy
A: 

What is list_t ? Is this plain C ? Be aware that one can simulate a "property" (sort of) in C++, so that calling runlist.next actually calls some method, it could be some iterator in disguise.

Vicky's answer seems more probable to me, though.

leonbloy
+1  A: 

printf() does not modify its variadic arguments. However, printf() is an operation of sufficient cost to expose races caused by no (or improper) locking between threads.

What you want to use is a mutex:

pthread_mutex_t thread_lock = PTHREAD_MUTEX_INITIALIZER;

void *thread_func(void *threadarg)
{
    thread_overview_control *toc = (thread_overview_control *)threadarg;

    pthread_mutex_lock(&thread_lock);
    printf("%d\n", toc->runlist.next);
    printf("%d\n", toc->runlist.next);
    pthread_mutex_unlock(&thread_lock);

    ....

In that example, pthread_mutex_lock() will block if another thread has the lock. If your function can do other useful work while waiting for the lock to become available, try pthread_mutex_trylock(), perhaps in a while() loop.

Just make sure each thread can get to the mutex, by making it global (or putting it in a structure that each can access). It is equally important to initialize your mutex with PTHREAD_MUTEX_INITIALIZER, or you run the risk of a lock being held without any thread actually holding it.

Whenever you read or write to *toc, you need to acquire the lock.

Tim Post
+1  A: 

Try to run your program under valgrind. It will point out any memory-related errors you might have.

Bad Sector
+1  A: 

Although a race condition is one possible reason, it sounds like your problem is a little more consistent than I would expect to see with that explanation.

Another possibility is a plain old wild pointer. How are you initialising toc? If it ends up pointing into released stack memory, the first printf() call could quite easily stomp on it.

caf