1

質問1:

RCU ロックを紹介する記事で、彼はパブリッシュ/サブスクライブ メカニズムを記述しています。しかし、rcu_assign_pointer()について質問があります。この記事で、彼は次のように述べています。

1 p->a = 1;
2 p->b = 2;
3 p->c = 3;
4 rcu_assign_pointer(gp, p);

rcu_assign_pointer() は新しい構造体を公開し、コンパイラと CPU の両方に、p によって参照されるフィールドへの割り当ての後に gp への割り当てを強制的に実行させます。

しかし、コンパイラと CPU はpが割り当てられたことをどのように知ることができますか?たとえば、p->a と p->b を初期化した場合、コンパイラと CPU は 2 つの状況をどのように区別するのでしょうか?

situation 1:
1 p->a = 1;
2 p->b = 2;
3 p->c = 3;
4 rcu_assign_pointer(gp, p);

situation 2:
1 p->a = 1;
2 p->b = 2;
3 rcu_assign_pointer(gp, p);

質問2:

読み取り側のクリティカル セクションについては、連続してデータを読み取るリーダーがいる場合、ライターはそれらを待つ必要がありますか、それともライターは同期操作を実行できませんでしたか? はいの場合、読者は常に古いバージョンを読みますか?

4

1 に答える 1

0

質問 1 への回答: rcu_assign_pointer() は、実装/コードで rcu_assign_pointer() ステートメントの前に行われた 'p' のフィールドへの変更が前に CPU パイプラインで実行されるように、コンパイラにマシン命令を最適化しないように指示します。 'gp' への 'p' の割り当て。これにより、'gp' が割り当てられると、'p' のすべてのフィールド、つまり開発者が割り当てることを選択した 'gp' が実際に割り当てられます。

さらに説明するために、次のコードを取り上げます。このコードの目的は、呼び出し元に 'y' を返すことです。

void my_func(struct foo **y) { struct foo *x = malloc(sizeof (struct foo)); x->val1 = 1; *y = x; x->val2 = 2; return; }

開発者は、上記の代入ステートメントの順序を気にする必要はありません。開発者の意図は、単に 2 つの値で満たされた *y を返すことだからです。したがって、上記のようなコードが与えられた場合、コンパイラは 3 つの代入ステートメントを CPU パイプラインで並列に実行することを選択でき、正確性を損なうことはありません。

ここで、rcu タイプの作業を行うときに同様の割り当てステートメントを使用すると、コンパイラは同じ種類の最適化を選択する可能性があり、そのためリーダーは「部分的に初期化された」「gp」になる可能性があります。rcu_assign_pointer() は、すべての p のフィールドが初期化された後に 'p' を 'gp' に割り当てるという開発者の意図が保持されるように、割り当ての順序が維持されるようにします。

これは、開発者が 'p' を 'gp' に割り当てる前に、p->c を割り当てずに p->a と p->b のみを割り当てることを選択した場合、それが gp が取得するものであることを示しているはずです - a部分的に初期化された構造。

質問 2 への回答:

于 2015-09-12T01:45:02.787 に答える