web-dev-qa-db-ja.com

共有変数の大きなセットへのスレッドセーフなアクセスを容易にする方法は?

私は2つのセット(入力と出力)を70個の32ビット整数変数と70個のブール(全部で140個の変数)持っています。これらは、3つのスレッドからアクセスして変更する必要があります。 これらの140個の変数のすべてへのスレッドセーフな読み取り/書き込みアクセスを、単一のミューテックスの下ですべてロックせずに容易にする適切な設計パターンは何ですか(これはパフォーマンスが低下することを期待しています)?

パフォーマンス要件に関する詳細:

  • スレッド1(「CANシリアル通信」)は、70の入力共有変数の1つに対する更新された値を含むパケットを1msごとにハードウェアセンサーから受信します。スレッドはその値で変数を更新します。また、5msのスレッド1ごとに、70個の出力変数すべてのコピーを作成する必要があります。

  • スレッド2(「コントローラー」)は、10msごとにすべての入力変数のコピーを作成し、すべての出力変数を上書きします。

  • スレッド3(「GUI」)は、500msごとにすべての入出力変数のコピーを作成します。

  • システムは ARM Cortex-A8 600Mhzで動作します。

1つの解決策は、140の変数ごとにミューテックスロックを作成することですが、これはハックのように感じられます。次に、変数を140のゲッターとセッターでクラスにラップしますが、これも醜いようです。


std::atomic

他の選択肢はstd::atomic。しかし、私はそれが高度で複雑な機能であると感じています。たとえば、IRCで次のスニペットの例はスレッドセーフではないことを直感的に見ても、

typedef struct MyStruct {
        std::atomic<int> a;
        std::atomic<int> b;
}

std::atomic<MyStruct> atomic_struct;
atomic_struct.a = 1;
atomic_struct.b = 2;

// Make a copy of `atomic_struct`
Mystruct normal_struct;
normal_struct = atomic_struct;

// Edit the values of the copied struct and copy the changes back to the `atomic_struct`.
normal_struct.a = 100;
normal_struct.b = 200;
atomic_struct = normal_struct;
4
DBedrenko

コメントが答えに変わりました:

1つのミューテックスの下ですべてをロックすることでパフォーマンスを心配するのは正しいことですが、より良い解決策は、ロック内で可能な限り少ないことを確認することです。

スレッド1は値とインデックスの準備ができている必要があり、実際には単一の書き込みのみを実行します。スレッド2は、クラスの非共有ローカルインスタンスで動作し、それを共有インスタンスと交換します。スレッド3には、共有を各更新にコピーする非共有ローカルインスタンスもあります。

4
Caleth

特定のケース(すべての変数がスカラー、つまり整数またはブール値)の場合、C++ 11の atomic 機能の使用を検討できます。最近のGCCまたはClangコンパイラが必要です。

したがって、std::atomic_boolを使用します。これらの変数のタイプについてはstd::atomic_intなど... atomic_loadatomic_store を使用します。単純な使用法は、これらのアトミック変数へのすべてのアクセス(または割り当て)に対してatomic_loadatomic_storeを体系的に使用することです。

変数のセット全体を処理する操作(たとえば、すべての変数のコピーを作成する)の場合、グローバルミューテックスが必要になります。

もちろん、パフォーマンスの低下はありますが、明示的なミューテックスを使用するよりもはるかに低くなります(àla std :: mutex )。私はあなたのプラットフォームを正確には知りませんが、各アクセスは通常の非原子データの場合よりも数十倍遅くなると思います。ベンチマークする必要があります。ほとんどのミューテックス実装(少なくともLinuxでは)は、 futex(7) のようなより複雑な機械に結合されたアトミックスカラーに相当するマシンを使用しています(これが、実際にはミューテックスがアトミックより遅い理由です)。

または、(意味のある方法で)変数を一緒にグループ化することを検討し、変数の小さなサブセット(たとえば、半ダース)を制御するミューテックスを用意します。