2

私は、互いにメッセージを送信する複数のタスクで構成される組み込み制御システムを C で作成しています (かなり一般的なイディオムだと思います!)。

  • きちんとしている
  • ジェネリックです
  • 比較的効率的です
  • 最も重要なこと:プラットフォームに依存しない (具体的には、厳密なエイリアスやアライメントの問題に違反しない)

概念的には、各メッセージ タイプを個別の構造体定義として表現したいと思います。また、次の関数 (簡略化) を備えたシステムが必要です。

void sendMsg(queue_t *pQueue, void *pMsg, size_t size);
void *dequeueMsg(queue_t *pQueue);

ここで、aqueue_tはノードのリンク リストで構成され、それぞれにchar buf[MAX_SIZE]フィールドがあります。私が使用しているシステムにはmalloc()実装がないため、空きノードのグローバル プールと、次のいずれかが必要になります (認識された問題は太字で示されています)。

  1. sendMsg()memcpy空きノードのバッファへの受信メッセージの処理を行います。
    私の理解では、呼び出し元が戻り値dequeueMsg()をさらに処理しない限り、これにはアライメントの問題が発生します。memcpy
  2. または、呼び出し元 (送信者) が適切な型へのポインターにキャストする次の空きノードのvoid *getFreeBuffer()を返す関数があります。私の理解では、これには途中でアライメントの問題があり、途中でアライメントの問題を回避するためにまだ後が必要です.buf[]
    memcpydequeueMsg()
  3. またはノードのバッファqueue_tを (eg) として再定義しuint32_t buf[MAX_SIZE]ます。
    私の理解では、これは厳密なエイリアシングに違反しており、プラットフォームに依存しません。

私が見ることができる他の唯一のオプションは、すべてのメッセージタイプの結合を とともに作成することですがchar buf[MAX_SIZE]、これを「きれい」とは見なしません!

だから私の質問は、どうすればこれを適切に行うことができるのでしょうか?

4

2 に答える 2

2

これに対処する方法は、フリー リストを整列されたノードで完全に構成することです。実際、さまざまなサイズのノードに対して複数の空きリストがあるため、2 バイト、4 バイト、および 16 バイトの境界に整列されたリストがあります (プラットフォームは、1 つの SIMD ベクトルより大きい整列を考慮しません)。割り当ては、これらの値のいずれかに切り上げられ、適切に配置されたノードに配置されます。そのため、sendMsg は常にそのデータを整列ノードにコピーします。フリーリストは自分で書いているので、アライメントを簡単に強制できます。

また、#pragma または declspec を使用して、その char buf[MAX_SIZE] 配列を強制的に queue_t ノード構造体内の少なくとも 1 つのワード境界に揃えます。

もちろん、これは入力データが整列されていることを前提としていますが、何らかの理由で (たとえば) 整列から 3 バイト離れていると予想されるメッセージを渡している場合は、モジュラスを使用して常にそれを検出し、オフセットをに返すことができます。フリーノード。

その基礎となる設計により、上記のオプション 1 と 2 の両方をサポートするインターフェイスが用意されています。繰り返しますが、入力データは常にネイティブにアラインされていることを前提としているため、もちろん、デキューはアラインされたポインターを返します。ただし、奇妙に整列されたデータが必要な場合は、フリー ノードにオフセットして、オフセット ポインターを返します。

これにより、void * を処理し続けるため、厳密なエイリアシングの問題を回避できます。(ただし、一般的には、独自のメモリ アロケータを作成するときは、厳密なエイリアシング要件を緩和する必要があると思います。これは、性質上、型が内部的にぼやけているためです。)

于 2009-08-17T22:59:20.160 に答える
1

1がアラインメントの問題を提示する理由がわかりません。各要素がメッセージ構造体 (おそらく 32 ビットまたは 64 ビット) で発生する自然最大の単一プリミティブ型にアラインされている限り、各buf[MAX_SIZE]要素の内容は問題ではありません。メッセージタイプは; 常にそのサイズに揃えられるためです。

編集

実際には、それよりもさらに簡単です。メッセージ キュー内の各要素はMAX_SIZE長さがあるため、各メッセージをそれ自体で開始すると仮定するとbuf(つまり、メッセージが MAX_SIZE 未満の場合はパックしない)、キュー内のすべてのメッセージは少なくとも次の境界で開始されます。それ自体と同じくらい大きいため、常に正しく配置されます。

于 2009-08-17T22:58:38.463 に答える