Compare and swap
От: RQ  
Дата: 17.09.16 14:21
Оценка: 53 (3)
Добрый день,

чем больше читаю про lock-free структуры данных и алгоритмы, тем больше путаницы и не уверенности порождаю в своем сознании. Дошло до того, что поймал себя на мысли, что не могу однозначно ответить на ряд простых с виду вопросов. Буду очень признателен, если кто то поможет упорядочить ту кашу, которая у меня сейчас вертится в голове. Ниже представлены типичные паттерны использования операции CAS:

1.
public static T
    Change<T>(this T source, Func<T, T> operation)
    where T : class
    {
        T original, value;
        do
        {
            original = source;
            value = operation(original);
        }
        while (Interlocked.CompareExchange(ref source, value, original) != original);
        return original;
    }


2.
public static T
    Change<T>(this T source, Func<T, T> operation)
    where T : class
    {
        var original = source;
        while (true)
        {
            var value = operation(original);
            if (Interlocked.CompareExchange(ref source, value, original) == original)
                break;
        }
            
        return original;
    }


3.
private double foo;

public double
    Foo {
    get { return this.foo; }
    set
    {
        while (true)
            if (Interlocked.CompareExchange(ref this.foo, this.foo + value, this.foo) == this.foo)
                break;
    }
}


Вопросы:

1. Имеет ли какое то значение порядок операций выделенных жирным в первом и втором примерах?
2. Тот же самый вопрос, но в случае использования подобного кода для value type?
3. Есть ли концептуальная разница между 1, 2 и 3 вариантами (за исключением первых двух вопросов) — меня смущает, что в ряде примеров авторы сохраняют исходное значение в отдельную переменную и так же поступают с вычисляемым значением, а в других нет.
4. Правильно, ли я понимаю, что CAS применяется, только при необходимости модификации shared данных с учетом возможных изменений произведенных другими потоками? Иными словами, в случае, если перезатирание данных последним потоком является нормальным поведением программы, использования CAS излишне?

UPD:
5. При использовании CAS для List<T> с целью сохранения производительности, стоит ли в обязательном порядке переопределять методы Equals для типа с которым работает список? На сколько это вообще разумно применять CAS для generic коллекций?

Заранее благодарю за ответы!
Отредактировано 17.09.2016 14:49 h1802486 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.