【问题标题】:Proper use of 'volatile' in this case (C)?在这种情况下正确使用“易失性”(C)?
【发布时间】:2013-03-03 01:36:54
【问题描述】:

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

读取/更新这些指针的线程是这样工作的:

  • 复制指针,只使用我们的副本,这样如果原始更改我们不会在过程中突然使用新的。
  • 根据我们的副本指向的值创建一个新指针。
  • 使用原子比较+交换将旧指针替换为新指针,除非另一个线程已经对其进行了更新。

我遇到的问题是,当我复制指针时,我收到一条警告:

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

编译后的代码似乎可以正常工作,但警告让我很困扰。我是否错误地使用了 volatile?假设我使用 volatile 没问题,我该如何删除警告?我不想在复制指针的声明上加上 volatile,没有其他线程会更新我们的副本,所以它真的不是 volatile。它在读/写结构时唯一的易失性。

这里有一些演示代码,只是演示了我的问题,我正在使用的实际代码要好得多,但也太大而无法发布。有一个明显的内存泄漏,暂时忽略它,我的真实用例正确地跟踪和管理内存。我只关心这个问题的“易失性”,我不是在我的演示中寻找要解决的错误。

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

【问题讨论】:

    标签: c atomic volatile


    【解决方案1】:

    这是因为volatile int * 不是“指向 int 的 volatile 指针”,而是“指向 volatile int 的指针”。比较const char *a = "foo";,那是指向常量字符数据的指针,而不是常量指针。

    因此,在您的情况下,我认为应该是 volatilething 指针,因为其中的字段可以“随机”更改(从一个线程的角度来看)。您也可以(正如您在评论中所说)移动 volatile 使其成为结构中的 int * volatile i;

    您也可以(当然)随时使用cdecl 来获得即时帮助来解决这些问题。

    【讨论】:

    • 嗯,做更多的研究,我不应该在结构中实际使用'int * volatile i'吗?似乎这就是我用来使指针本身易变的方法。进行更改也消除了我的警告...但我想确保它按我认为的方式工作...
    • 是不是因为他在赋值给copy的时候把一个指向volatile int的指针赋值给了一个non-volatile int?用法应该是 int copy = *(t->i);?
    • @tinman 如果我正在处理整数,那么是的。但这是一个更复杂的演示。实际上,我有一些结构,其中包含指向结构的指针,这些结构有几层深,任何级别的指针都可以被任意数量的线程更改,所以我需要指针本身是可变的。
    猜你喜欢
    • 1970-01-01
    • 2020-08-06
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-02
    相关资源
    最近更新 更多