これはCに適用されます(おそらく他の同様の非オブジェクト指向言語にも適用されます)。中央データストアと潜在的に同時アクセスがある場合、それを保護するには2つの方法があります。
いくつかのデータ要素を持つデータストアがあるとします...
struct MyStore
{
int data1, data2, data3, ...., dataN;
} store[M];
この例ではデータ型は同じですが、これが異なる型などで少し変化したものに適用されると想像してみましょう。これは、質問を単純にするためです。
他のユーザーにデータへのアクセスを許可するには、いくつかのことを行うことができます。
最初の方法の私の問題は、負担が発信者に課されることです。
2番目の問題は、少なくともCでは、最初にボイラープレートアクセサーの全負荷を書き、2番目にテストと設定のような複雑なものを書き込んだり、いくつかの操作を実行しながらデータのロックを保持する必要があることです。乱雑。例えば。方法2に必要
int GetData1(unsigned int index) {
int data;
ENTER_CR();
data = store[index].data1;
LEAVE_CR();
return data;
}
...
...
int GetDataN(unsigned int index) {
int data;
ENTER_CR();
data = store[index].dataN;
LEAVE_CR();
return data;
}
そして、すべてのセッターについて同じです。そして、複数のアイテムをアトミックに設定したい場合はどうなりますか?大変になる!
モジュール性とカプセル化のいくつかの利点を手に入れながら、柔軟なインターフェースをどうやって得るのですか?
スレッドセーフなインターフェース(OOPありまたはあり)を提供する場合、操作がアトミックにしたいレベルであることを確認する必要があります。単一のフィールドの設定または取得が、サポートしたいアトミック操作のレベルである場合、オプション1が機能します。 (一方で、intの取得と設定はとにかくアトミックです)
現実には、単純なデータオブジェクトがスレッドセーフを提供する設計の適切な場所ではない可能性があります。これは、データが使用されている「実際の」操作が何であるかを実際に知らないためです。スレッドセーフをカプセル化することもできますが、これはsingingだけではなく、doing何かがある場所である必要があります。
Cでは、クリーンなインターフェイスを作成するために別の言語で行うすべてのことを実行できます。必要なのは、少ない言語サポートで実行することだけです。
ボイラープレートアクセサーを避けたい場合は、すべての単純型をunionに格納します。列挙型フィールドID(つまり、unionの配列へのインデックス)による単一のアクセスがあり、呼び出し元は各フィールドの型を心配できます。
struct MyStore;
union Atom {
int i;
double d;
/* any other types */
};
/* access any type by index */
union Atom *field(struct MyStore *, int id);
複数の操作をアトミックイベントにバンドルする場合は、次のようにすることができます。
struct MyStore;
struct BatchOperation;
struct BatchOperation *startBatch(struct MyStore*);
void endBatch(struct BatchOperation*);
/* force client to call startBatch before accessing */
union Atom *field(struct BatchOperation *, int id);
ここでは、バッチ操作を開始するとストアがロックされ、終了するとロックが解除されます。
BatchOperation
ライフタイムの自動管理は行われないため、クライアントコードmustはバッチを終了するか、デッドロックを引き起こしますPS。上記で使用されている不透明なタイプに注意してください。unionおよびpublic関数のみがクライアントコードに完全に表示されます。これは実際にはカプセル化であり、恐怖の見積もりは必要ありません。