2013-03-14 101 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

相关问题