正确使用';挥发性';在这种情况下(C)?

正确使用';挥发性';在这种情况下(C)?,c,atomic,volatile,C,Atomic,Volatile,我有一个包含几个指针的结构。这些指针可以由几个不同的线程更改。这些线程通过更改指针来更新结构,使其指向另一个内存位置,而不会更改指向的值。根据我对volatile的理解,将结构中的这些指针声明为volatile是有意义的 读取/更新这些指针的线程的工作方式如下: 复制指针,仅使用我们的副本,这样,如果原始更改,我们不会在过程中途突然使用新的 根据复制指向的值创建一个新指针 使用原子比较+交换将旧指针替换为新指针,除非其他线程已经对其进行了更新 我遇到的问题是,当我复制指针时,会收到一条警告:

我有一个包含几个指针的结构。这些指针可以由几个不同的线程更改。这些线程通过更改指针来更新结构,使其指向另一个内存位置,而不会更改指向的值。根据我对volatile的理解,将结构中的这些指针声明为volatile是有意义的

读取/更新这些指针的线程的工作方式如下:

  • 复制指针,仅使用我们的副本,这样,如果原始更改,我们不会在过程中途突然使用新的
  • 根据复制指向的值创建一个新指针
  • 使用原子比较+交换将旧指针替换为新指针,除非其他线程已经对其进行了更新
我遇到的问题是,当我复制指针时,会收到一条警告:

警告:初始化将从指针目标类型中丢弃“volatile”限定符

编译后的代码似乎工作正常,但警告让我感到困扰。我是否使用volatile不正确?假设我可以使用volatile,那么如何删除警告?我不想把volatile放在copy指针的声明上,因为没有其他线程会更新我们的副本,所以它确实不是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;
}
#包括
#包括
#包括
类型定义结构{
挥发性int*i;
}事物;
void init(thing*t){
t->i=malloc(sizeof(int));
*(t->i)=1;
}
void*线程(void*args){
thing*t=args;
对于(int i=0;i<100;i++){
//这将生成“volatile”警告。但我不想
//*复制易失性,因为没有其他线程会更改“复制”。
//这是不正确的用法,还是我只需要做一些事情来删除
//警告?
int*copy=t->i;
int*new=malloc(sizeof(int));
*新=(*副本)+1;
//当旧x变得无法访问时,内存泄漏非常明显,这是一个演示,
//这是为解决问题而设计的真正程序。
//我们不关心它是否成功或失败来交换这个演示。
__同步布尔比较和交换(&(t->i),复制,新建);
}
}
int main(){
事物t;
初始化(&t);
pthread_t a;
pthread_t b;
pthread_create(&a,NULL,线程,&t);
pthread_create(&b,NULL,线程,&t);
pthread_join(a,NULL);
pthread_join(b,NULL);
返回0;
}

这是因为
volatile int*
并不意味着“volatile pointer to int”,而是意味着“pointer to volatile int”。比较
const char*a=“foo”,这是指向常量字符数据的指针,而不是常量指针

所以在你的例子中,我相信是
东西
指针应该是
易变的
,因为它中的字段可以“随机”(从一个线程的角度)更改。您还可以(如您在评论中所说)移动
volatile
使其成为
int*volatile i


当然,你也可以(随时)得到即时帮助来解决这些问题。

Hmm,做更多的研究,我真的应该在结构中使用“int*volatile I”吗?这似乎就是我用来使指针本身不稳定的原因。同时进行更改将删除我的警告。。。但我想确定它是按照我认为的方式工作的……是不是因为他在分配给复制时将一个指向易失性int的指针分配给了一个非易失性int?用法应该是int copy=*(t->i)@tinman如果我在处理ints,那么是的。但这是一个更复杂的演示。实际上,我有一些结构包含指向结构的指针,这些结构有两个层次,任何层次上的指针都可以被任意数量的线程更改,所以我需要指针本身是可变的。