C でスレッド間で動的データ転送とメモリ管理を行うにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/689514

  •  22-08-2019
  •  | 
  •  

質問

プラットホーム:ARM9

プログラミング言語 C

要件 - プレーン C、外部ライブラリなし、ブーストなし。

OS - REX RTOS

組み込みプラットフォームで 2 つのスレッドを実行しています -

  1. 1 つはドライバー レベルで、ハードウェアとのすべての通信とデータ転送を処理します。
  2. 2 番目のスレッドは、ハードウェアとの間でデータを使用するアプリケーションを実行します。

このアイデアは、アプリ スレッドをドライバー スレッドから切り離すことで、ハードウェア ドライバー スレッドのハードウェアと実装を変更しながら、アプリケーション スレッドへの影響を最小限に抑えられるようにすることです。

私の課題は、ハードウェアから受信したデータが動的である可能性があることです。実行時に決定されるため、ハードウェアとの各リクエストに対してアプリケーション スレッドがどれだけのメモリを確保する必要があるかは、事前にはわかりません。

私は、ドライバー スレッドがアプリケーション スレッドに、読み取るデータが多量にあることを通知できるのではないかと考えていました。次に、アプリケーション スレッドはメモリを割り当て、ドライバー スレッドにデータの読み取りを要求します。その後、アプリケーション スレッドがデータを適切に処理することになります。これにより、すべてのメモリ管理がアプリケーション スレッド内で行われます。

役に立ちましたか?

解決

カップルのオプションが気になります

1)アプリケーションでそれを解放し、ドライバのメモリををmalloc。しかし...我々は、リアルタイム要件に近づくものでmalloc関数の使用を避ける傾向にあります。あなたはmalloc関数/自由へのアクセス権を持って、そして何の「リアルタイム」懸念やメモリの断片化の問題は、(すなわち、あなたのヒープが十分な大きさである)が存在しない場合、これはかなり簡単なアプローチです。ドライバは、単にメッセージ・キューを経由してアプリケーションのスレッドに割り当てられたポインタを送信して行われたときにアプリが空きメモリです。メモリリークのために気をつけてます。

2)リングまたは円形のバッファ。ドライバは完全に固定されたサイズのリングバッファを管理し、バッファの準備ができたときに、単にアプリケーションにメッセージを送信します。いくつかの詳細についてはこちらをご覧ください:循環バッファに。次に、アプリケーションは、アプリケーションのスレッドからリングバッファの詳細を隠すことができますドライバAPIを介して再び「利用可能」データをマークします。私たちは、あなたが説明するように要件の非常に似セットを持って我々のドライバーの1のためにこのアプローチを使用しています。このケースでは、などのリングバッファのための「最良」のサイズ、ドライバーでのオーバーフロー処理を、決定を気にする必要はあります。

幸運!

他のヒント

あなたはOSを指定しませんが、何らかの形で「スレッド」を持っています。それらの1つは、ドライバレベル(割り込みハンドラ)とアプリケーション(ユーザランド/カーネル)のような他の音である場合を除き。データも処理される前に、あなたのドライバとアプリが通信しているので、しかし、それは、いずれかの一致しません。

あなたの用語が混乱して有望ではありません。これは自作(RT)OSやないですか?

あなたは本当のOSを持っている場合は、

、ユーザーランドにドライバと手渡しデータを書き込むための方法が確立されています。ドキュメントを読むか、参照として既存のドライバのいずれかを使用します。

これは、カスタムOSの場合は、

、あなたはまだアイデアのために他のオープンソースドライバを参照することができますが、はっきりと物事をとして便利な設定はありません。ドライバコード内のすべてのメモリを事前に割り当て、それが到着するデータとそれを記入し、アプリケーション・コードにそれを渡します。メモリの量は、あなたのアプリがデータを処理することができますどのくらいの速の機能を、あなたが受け入れることを計画してデータの最大量となり、そしてどのくらいの内部データキューイングは、あなたのアプリケーションをサポートするために必要とされます。

このことCは、私はアプリは、ドライバとのコールバックを登録するために持つまで終了しています。コールバックの目的は、ドライバがデバイスからそれを読み出した後、データを処理することです。ドライバは、メモリすなわち割り当てメモリを管理するコールバックを呼び出し、最終的にメモリを解放します。さらに、コールバックは専用メモリ上の権限を読み取りました。そのため、アプリは、理想的にはちょうどすぐにコールバックから独自のメモリと、出口にバッファの内容をコピーする必要があります。そして、いつ、どのようにそれが希望するデータを処理するために自由である。

私は、コールバックが戻ることが想定されるアプリコールバックの用途にそれを明確にするためにドキュメントを更新し、メモリはもはや有効と見なされるべきではありません。コールバックは、他の方法を使用した場合、動作は未定義です。

私が最初に考えたのは、循環バッファーを使用することです。以下にコード例を示します。これを独自の用途に合わせて自由に調整してください。おそらくグローバル変数は必要ないでしょう。#define は必要ないかもしれません:

#define LENGTH (1024)
#define MASK (LENGTH-1)
uint8 circularBuffer[ LENGTH ];
int circularBuffer_add = 0;
int circularBuffer_rmv = 0;

void copyIn( uint8 * circularBuffer, uint8 * inputBuffer, int n ) {
    int i;
    for( i = 0; i < n; i++ ) {
        circularBuffer[ circularBuffer_add ] = inputBuffer[ i ];
        circularBuffer_add = ( circularBuffer_add + 1 ) & MASK;
    } 
}

void copyOut( uint8 * circularBuffer, uint8 * outputBuffer, int n ) {
    int i;
    for( i = 0; i < n; i++ ) {
        outputBuffer[ i ] = circularBuffer[ circularBuffer_rmv ];
        circularBuffer_rmv = ( circularBuffer_rmv + 1 ) & MASK;
    } 
}

また、上記のコードは、データの単位がデータ型「uint8」であることを前提としています。他のデータ型を使用するように変更できます。または、それを汎用にして memcpy() を使用してcircularBufferにコピーすることもできます。

このコードの主な特徴は、add および rmv ptr をどのように処理するかです。


上記のコードで動作するようになったら。 ある時点で、ハードウェアからのすべての読み取りをプラットフォームの使用に切り替えることをお勧めします。 ダイレクトメモリアクセス API.

それは 上記のコードは DMA に比べて多くのサイクルを使用するため、ダイレクト メモリ アクセスに切り替えることが重要です これはほぼゼロサイクルを使用します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top