2010-05-21 110 views
2

我們有下面的代碼行:讀一個變量混淆了它?

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

這些定義:

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; 

我想要做的就是實現用戶線程。出於某種原因,上述代碼在我們的測試運行崩潰時的輸出是:

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

這是怎麼發生的?我們所做的只是讀取一個變量。 奇怪的是,沒有printf的,沒有崩潰。這是怎麼回事?

+0

你的意思是,如果你只需要調用 toc-> runlist.next toc-> runlist.next 沒有崩潰? 怎麼樣: INT someint someint = toc-> runlist.next someint = toc-> runlist.next 這是否也產生崩潰? – 2010-05-21 12:20:43

回答

1

printf()不修改其可變參數。然而,printf()是一個足夠的代價暴露線程之間沒有(或不正確)鎖定導致的競爭的操作。

要使用什麼是互斥:

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); 

    .... 

在那個例子中,如果另一個線程已鎖定pthread_mutex_lock()將阻止。如果您的功能可以在等待鎖定可用時執行其他有用的工作,請嘗試pthread_mutex_trylock(),或許在while()循環中。

只要確保每個線程都可以通過使其成爲全局變量(或將其放置在每個可以訪問的結構中)即可獲得互斥體。使用PTHREAD_MUTEX_INITIALIZER初始化您的互斥鎖也同樣重要,否則您可能會冒着在沒有任何線程實際持有它的情況下持有鎖的風險。

每當您讀取或寫入*toc時,您都需要獲取該鎖。

3

很可能是另一個線程正在訪問(和更改)兩次調用printf()之間的變量。如果刪除printf語句,則時間更改並且行爲不同。

如果數據確實被多個線程訪問,則需要使用互斥鎖來保護數據。

+0

但是,如果兩個'printf'確實是一個接一個,那麼發生這種情況的可能性就會比較低...... – leonbloy 2010-05-21 20:32:59

0

什麼是list_t?這是簡單的C嗎?請注意,在C++中可以使用simulate a "property"(有點),所以調用runlist.next實際上會調用某種方法,它可能是一些僞裝的迭代器。儘管如此,薇琪的回答似乎更有可能。

1

嘗試在valgrind下運行你的程序。它會指出你可能有的與內存有關的錯誤。

1

雖然競爭條件是一個可能的原因,但聽起來您的問題比我期望看到的解釋稍微一致。

另一種可能性是普通的老式野指針。你是如何初始化toc?如果它最終指向已釋放的堆棧內存,則第一個printf()調用可能會很輕鬆地踩到它。