10

編集: ST では、初心者向けに 2 つ以上のリンクを投稿することは許可されていません。参照が不足していて申し訳ありません。

グローバル状態の変更の検出がパフォーマンスに関連する C アプリケーションでロックのオーバーヘッドを削減しようとしています。最近、このトピックについてかなり多くのことを読んでいますが (たとえば、H. Sutter などから多くのことを読んでいます)、自分の実装について確信が持てません。複数のスレッド間で共有されるデータからスレッド ローカル データを更新するために、 CASのような操作とDCLを組み合わせてCache-Line Alignedグローバル変数をチェックし、偽共有を回避したいと考えています。自信がないのは主に

  1. Type-Attributesに関する GNU ドキュメントの解釈に失敗しました
  2. STまたは1でのキャッシュラインへの整列およびキャッシュラインサイズの認識など、Cに簡単に変換できる文献や例を見つけることができないようです(1は答えているようですが)私の質問は、実装に自信がありません)
  3. 私のCの経験は限られています

私の質問:

  1. タイプ属性のドキュメントには次のように記載されています。

    この属性は、指定された型の変数の最小アラインメント (バイト単位) を指定します。たとえば、宣言は次のとおりです。

    (宣言については、型属性のドキュメントを参照してください)

    struct S コンパイラーに、型が割り当てられている、または割り当てられる予定の各変数がmore_aligned_int、少なくとも8-byte境界で割り当てられ、整列されることを (できる限り) 保証するように強制します。SPARC では、型のすべての変数struct Sを境界に整列させる8-byteことで、コンパイラは型 struct S の変数を別の変数にコピーするときに ldd および std (ダブルワードのロードとストア) 命令を使用できるようになり、実行時の効率が向上します。

    struct Sそれは、またはの始まりが常に境界more_aligned_intに揃えられるということですか? 8-byte正確に 64 バイトを使用するためにデータがパディングされるという意味ではありませんよね?

  2. struct cache_line_aligned1. のすべてのインスタンス(以下のコード例 1を参照) が境界上に位置合わせされ、正確に 1 つのキャッシュ ラインを使用することが true であると仮定します64-byte(キャッシュ ラインが64 bytes長さであると仮定します) 。

  3. 型宣言に使用typedefしても、のセマンティクスは変更されません__attribute__ ((aligned (64)))(以下のコード例 2を参照)。

  4. aligned_malloc構造体がで宣言されている場合、構造体をインスタンス化するときに使用する必要はありません__attribute__ ...

// Example 1
struct cache_line_aligned {
  int version;
  char padding[60];
} __attribute__ ((aligned (64)));

// Example 2
typedef struct {
  int version;  
  // place '__attribute__ ((aligned (64)))' after 'int version'
  // or at the end of the declaration 
  char padding[60];
} cache_line_aligned2 __attribute__ ((aligned (64)));

最後に、キャッシュラインにアラインされたアプローチを使用して、グローバル状態が他のスレッドによって変更されたかどうかを効率的にチェックする関数のスケッチを示します。

void lazy_update_if_changed(int &t_version, char *t_data) {
  // Assuming 'g_cache_line_aligned' is an instance of 
  // 'struct cache_line_aligned' or 'struct cache_line_aligned2' 
  // and variables prefixed with 't_' being thread local 
  if(g_cache_line_aligned.version == t_version) {
    // do nothing and return
  } else {
    // enter critical section (acquire lock e.g. with pthread_mutex_lock) 
    t_version = g_cache_line_aligned.version
    // read other data that requires locking where changes are notified 
    // by modifying 'g_cache_line_aligned.version', e.g. t_data
    // leave critical section
  }
} 

長い投稿で申し訳ありません。

ありがとうございました!

4

1 に答える 1

7

アラインされた型を定義する場合、たとえば 8 バイト境界にアラインされた場合、コンパイラはパディングによって型のサイズをアラインメントの倍数 (ここでは 8 バイトの倍数) にする必要があります。

その理由は簡単です。その整列された型の配列を定義したいとします。当然、そのすべての要素も同様に整列する必要があります。そのため、パディングがある場合があります。

ここに少しデモンストレーションがあります:

#include <stdio.h>

struct cache_line_aligned {
  int version;
//  char padding[60];
} __attribute__ ((aligned (64)));

int main(void)
{
  struct cache_line_aligned s;
  struct cache_line_aligned a[2];
  printf("sizeof(struct cache_line_aligned) = %d\n", (int)sizeof(struct cache_line_aligned));
  printf("sizeof(s) = %d\n", (int)sizeof(s));
  printf("sizeof(a[0]) = %d\n", (int)sizeof(a[0]));
  printf("sizeof(a) = %d\n", (int)sizeof(a));
  return 0;
}

出力 ( ideone ):

sizeof(struct cache_line_aligned) = 64
sizeof(s) = 64
sizeof(a[0]) = 64
sizeof(a) = 128

上記のコードのように、struct cache_line_aligned非動的 (IOW、ビアなどではない)のインスタンスを作成すると、整列されます。malloc()

C 標準 (1999 年以降)malloc()では、 、calloc()およびについて次のように規定されていrealloc()ます。

The pointer returned if the allocation succeeds is suitably aligned so that
it may be assigned to a pointer to any type of object and then used to
access such an object or an array of such objects in the space allocated
(until the space is explicitly deallocated).

上記の構造体のような人為的に整列/パディングされた型は含まれません。これは、C 標準のany type of objectようなものがないためです。__attribute__ ((aligned (64)))これは GNU 拡張です。任意の配置で動的に割り当てられたオブジェクトの場合、適切なメモリ割り当て関数を使用するか、手動で配置を行う必要があります (より多くのメモリを割り当ててからポインター値を「配置」することにより)。

于 2012-09-26T06:03:50.187 に答える