开发者

Reading a variable messes it up?

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. 开发者_C百科 And the strange thing is, without printf's there are no crashes. What's going on?


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.


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.


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


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜