3

私はいくつかのポインタを保持する構造を持っています。これらのポインタは、いくつかの異なるスレッドで変更できます。これらのスレッドは、別のメモリ位置を指すようにポインターを変更することによって構造体を更新します。ポインターが指す値は決して変更しません。揮発性に関する私の理解に基づいて、構造体でこれらのポインターを揮発性として宣言することは理にかなっています。

これらのポインターを読み取り/更新するスレッドは、次のように機能します。

  • ポインタをコピーし、コピーのみを使用します。元の変更がプロセスの途中で突然新しいものを使用しないようにします。
  • コピーが指すものの値に基づいて新しいポインターを作成します。
  • 別のスレッドが既に更新していない限り、アトミック比較+スワップを使用して古いポインターを新しいポインターに置き換えます。

私がぶつかっている問題は、ポインターのコピーを作成すると、警告が表示されることです。

警告: 初期化により、ポインタ ターゲット タイプから '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;
}
4

1 に答える 1

3

これは、volatile int *「int への volatile ポインター」という意味ではなく、「volatile int へのポインター」を意味するためです。Compare const char *a = "foo";、これは定数ポインターではなく、定数文字データへのポインターです。

したがって、あなたの場合、その中のフィールドは(1つのスレッドの観点から)「ランダムに」変更される可能性があるため、それはthingポインタであるべきだと思います。volatile(コメントで言うように)を移動して構造体volatileにすることもできますint * volatile i;

(もちろん) いつでもcdeclを使用して、これらのことを理解するための即時のヘルプを取得することもできます。

于 2013-03-14T15:51:50.237 に答える