То, почему делает, Взаимно блокировалось. CompareExchange <T> только поддерживает ссылочные типы?

Отказ от ответственности: Мои сообщения являются, по-видимому, всегда подробными. Если Вы, оказывается, знаете ответ на вопрос о заголовке, не стесняйтесь просто отвечать на это, не читая мое расширенное обсуждение ниже.


System.Threading.Interlocked класс предоставляет некоторые очень полезные методы для помощи в записи ориентированного на многопотоковое исполнение кода. Один из более сложных методов CompareExchange, который может использоваться для вычислений рабочего общего количества, которое может быть обновлено от нескольких потоков.

Начиная с использования CompareExchange немного хитро, я думал это скорее идея здравого смысла обеспечить некоторые вспомогательные методы для него:

// code mangled so as not to require horizontal scrolling
// (on my monitor, anyway)
public static double Aggregate
(ref double value, Func<double, double> aggregator) {
    double initial, aggregated;

    do {
        initial = value;
        aggregated = aggregator(initial);
    } while (
        initial != Interlocked.CompareExchange(ref value, aggregated, initial)
    );

    return aggregated;
}

public static double Increase(ref double value, double amount) {
    return Aggregate(ref value, delegate(double d) { return d + amount; });
}

public static double Decrease(ref double value, double amount) {
    return Aggregate(ref value, delegate(double d) { return d - amount; });
}

Теперь, возможно, я просто виновен в том, чтобы быть универсально-счастливым (я признаю, это часто верно); но действительно чувствует себя глупым мне ограничить функциональность, предоставленную вышеупомянутыми методами double значения только (или, более точно, чтобы я должен был записать перегруженные версии вышеупомянутых методов для каждого типа, который я хочу поддерживать). Почему я не могу сделать этого?

// the code mangling continues...
public static T Aggregate<T>
(ref T value, Func<T, T> aggregator) where T : IEquatable<T> {
    T initial, aggregated;

    do {
        initial = value;
        aggregated = aggregator(initial);
    } while (
        !initial.Equals(
            Interlocked.CompareExchange<T>(ref value, aggregated, initial)
        )
    );
}

Я не могу сделать этого потому что Interlocked.CompareExchange<T> по-видимому, имеет a where T : class ограничение, и я не понимаю почему. Я имею в виду, возможно, это - потому что уже существуют перегрузки для CompareExchange это принимает Int32, Int64, Double, и т.д.; но это едва кажется хорошим объяснением. В моем случае, например, было бы довольно удобно смочь использовать Aggregate<T> метод для выполнения широкого спектра атомарных вычислений.

7
задан Dan Tao 11 February 2010 в 01:06
поделиться

3 ответа

Interlocked.CompareExchange предназначен для реализации с помощью собственных атомарных инструкций, предоставляемых непосредственно процессором. Бессмысленно, чтобы нечто подобное использовало блокировку внутри (оно предназначено для сценариев без блокировок).

Процессоры, предоставляющие атомарную инструкцию сравнения, естественно, поддерживают ее в виде небольших, "регистрового размера" операций (например, самая большая инструкция сравнения-обмена в процессоре Intel x64 - cmpxchg16b, которая работает со 128-битными значениями).

Произвольный тип значения может быть потенциально больше этого, и сравнение-обмен с ним может быть невозможен с помощью одной инструкции. Сравнить-обменять ссылочный тип очень просто. Независимо от его общего размера в памяти, вы будете сравнивать и копировать маленький указатель известного размера. Это также верно для примитивных типов, таких как Int32 и Double- все они маленькие.

12
ответ дан 6 December 2019 в 21:13
поделиться

Я подозреваю, что Interlocked.CompareExchange просто выполняет атомарную замену указателя под капотом.

Попытка сделать это с типом значения, скорее всего, не даст ожидаемых результатов.

Можно, конечно, упаковать типы значений в объект перед их использованием.

-1
ответ дан 6 December 2019 в 21:13
поделиться

Потому что эта перегрузка специально предназначена для сравнения и обмена ссылками. Он не выполняет проверку равенства с помощью метода Equals (). Поскольку у типа значения никогда не будет ссылочного равенства со значением, с которым вы его сравниваете, я предполагаю, что они ограничили T классом, чтобы предотвратить неправильное использование.

1
ответ дан 6 December 2019 в 21:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: