私は、ロックフリーの単一リンクリストを実装する方法を考えてきました。そして正直なところ、私はそれを行うための多くの防弾方法を見ていません。使用するより堅牢な方法でさえ、CAS
ある程度のABA問題が発生することになります。
それで私は考え始めました。部分的にロックフリーのシステムは、常にロックを使用するよりも優れているのではないでしょうか。一部の操作はアトミックでロックフリーにすることができますか?それができれば、それでもスレッドセーフになるはずです。
だから、質問に。私は単純な単一リンクリストを考えています。2つの主な操作。 push
およびpop
。push
常に前面に挿入します。このようなもの:
void push(int n) {
T *p = new T;
p->n = n;
p->next = root;
root = p;
}
そして、常に最初の要素を取るポップ。このようなもの:
T *pop() {
T *p = root;
root = root->next;
return p;
}
明らかに、プッシュは自明ではないので、単純なロックフリーのアプローチはおそらく起こらないでしょう。しかし、ポップはおそらく実行可能に見えます。gcc-intrinsicsを使用して、私はこれについて考えました:
T *pop() {
return __sync_lock_test_and_set(&root, root->next);
}
機能的に同等ですか?うん。ロックフリー?うん。スレッドセーフ?わからない。私の腸の反応はノーです、そしてここに理由があります。
test_and_set
のパラメータの1つがメモリを逆参照する必要があるという事実が心配です。ルートがroot->next
との間で変更された場合はどうなりますか__sync_lock_test_and_set
。
このコードはこれと同等だと思います:
T *pop() {
T *temp = root->next;
// are we broken if a push/pop happens here?
return __sync_lock_test_and_set(&root, temp);
}
だから、私が言ったように、私はこのコードが正しくないと思います。しかし、私が正しい結論を導き出していることを誰もが確かに言うことができます(うまく機能するものを書き留めるのは嫌です)。私が思うようにそれが実際に壊れている場合。簡単な解決策はありますか?