2013-03-14 51 views
3

我有一個結構,持有幾個指針。這些指針可以被幾個不同的線程改變。這些線程通過更改指針來更新結構,以便它指向另一個內存位置,它們永遠不會更改指向的值。根據我對易失性的理解,將結構中的這些指針聲明爲volatile是有意義的。在這種情況下正確使用'volatile'(C)?

讀/更新這些指針的線程的工作是這樣的:

  • 複製指針,只能用我們的副本,如果原來的變化,我們不會突然半途過程中使用的新的方式。
  • 根據我們的副本指向的值創建一個新的指針。
  • 使用原子比較+交換替換舊的指針與新的,除非另一個線程已經更新它。

我打的問題是,當我讓我的指針的副本,我得到一個警告:

警告:初始化拋棄「揮發」指針目標類型的限定詞

編譯的代碼似乎工作正常,但警告困擾我。我是否正確使用volatile?假設我使用volatile是好的,我該如何刪除警告?我不想將volatile寫入複製指針的聲明中,其他線程都不會更新我們的副本,所以它實際上不會變化。它在讀取/寫入結構時唯一不穩定。

下面是一些簡單演示我的問題的演示代碼,我使用的實際代碼更好,但也太大而無法發佈。有一個明顯的內存泄漏,現在忽略它我真正的用例正確地跟蹤和管理內存。我只關心這個問題的'volatile',我沒有在我的演示中尋找bug來解決。

gcc -std=gnu99 -pthread test.c && ./a.out 
test.c: In function ‘the_thread’: 
test.c:22:25: warning: initialization discards ‘volatile’ qualifier from pointer target type [enabled by default] 

代碼:

#include <stdlib.h> 
#include <stdio.h> 
#include <pthread.h> 

typedef struct { 
    volatile int *i; 
} thing; 

void init(thing *t) { 
    t->i = malloc(sizeof(int)); 
    *(t->i) = 1; 
} 

void *the_thread(void *args) { 
    thing *t = args; 

    for (int i = 0; i < 100; i++) { 
     // This generates the 'volatile' warning. But I don't want to make 
     // *copy volatile since no other threads will ever change 'copy'. 
     // Is this incorrect usage, or do I just need to do something to remove 
     // the warning? 
     int *copy = t->i; 

     int *new = malloc(sizeof(int)); 
     *new = (*copy) + 1; 

     // Glaring memory leak as old x becomes unreachable, this is a demo, 
     // the real program this is for has the issue solved. 
     // We do not care if it succeeds or fails to swap for this demo. 
     __sync_bool_compare_and_swap(&(t->i), copy, new); 
    } 
} 

int main() { 
    thing t; 
    init(&t); 

    pthread_t a; 
    pthread_t b; 

    pthread_create(&a, NULL, the_thread, &t); 
    pthread_create(&b, NULL, the_thread, &t); 

    pthread_join(a, NULL); 
    pthread_join(b, NULL); 

    return 0; 
} 

回答

3

這是因爲volatile int *並不意味着 「揮發性指向int的指針」,它的意思是 「指向揮發性INT」。比較const char *a = "foo";,這是一個指向常量字符數據的指針,而不是一個常量指針。所以在你的情況下,我相信它是thing指針應該是volatile,因爲它中的字段可以「隨機」(從一個線程的角度來看)更改。你可以(如你在評論中所說)移動volatile使其在結構中成爲int * volatile i;

您可以(當然)總是使用cdecl也可以立即獲得幫助。

+0

嗯,做更多的研究,不應該在結構中實際使用'int * volatile i'嗎?這似乎是我用來使指針本身不穩定。也做出改變消除了我的警告......但我想確定它是如何工作的我認爲它的確如此...... – Exodist 2013-03-14 16:04:10

+0

是不是因爲他將指針分配給非易失性int時將volatile指針分配給非易失性int複製?用法應該是int copy = *(t-> i);? – tinman 2013-03-14 20:17:33

+0

@tinman如果我在處理整數,那麼是的。但這是一個更復雜的演示。實際上,我有一些結構指針指向結構深達幾級的結構,任何級別的指針都可以被任意數量的線程改變,所以我需要指針本身是不穩定的。 – Exodist 2013-03-14 21:45:18

相關問題