Стандартная структура данных union / find или Disjoint-set имеет очень хорошие времена выполнения (эффективно O(1)
) для однопоточных случаев. Однако что такое валидность / производительность в многопоточных случаях? Я думаю , что он полностью действителен даже без блокировки или каких-либо атомарных операций, кроме операций записи размером атомного указателя.
Кто-нибудь видит проблемы со следующей логикой?
Сначала я предположу, что записи размером с указатель являются атомарными. Исходя из этого, нетрудно утверждать, что вы можете безопасно запускать функцию find
в нескольких потоках, поскольку единственные обновления, которые будут происходить, - все они имеют одно и то же значение. Если вы позволите функции find
возвращать ответ, который был истинным при его вызове (в отличие от того, когда он возвращался), нетрудно утверждать, что многие find
s и один union
могут выполняться одновременно время; аргумент для find
s не меняется, а union
только обновляет корни, а find
s никогда не обновляет корни.
Что касается оставшегося случая (несколько union
с), я думаю, что это работает, но я не уверен в этом.
Кстати: я не требую, чтобы решение было таким же эффективным, как однопоточная версия. (Чтобы избежать блокировок / атомарных, я также хочу отказаться от глобально связного состояния.)
edit: если взглянуть по-другому, случаи множественного объединения не работают, потому что если сторона, которая не является новым корнем, объединена с чем-то другим (также не как корень), то вы можете вырезать это с другой стороны второго союза.
A = find(a) // union 1
B = find(b) // union 1
----
X = find(x) // union 2 (x == a) -> (X == A) -> (X.par aliases A.par)
Y = find(y) // union 2
X.par = Y // union 2
----
A.par = B // union 1
это можно обойти с помощью CAS :
while(!CAS(A == A.par, B)) A = find(A);