Отказ от ответственности: Мои сообщения, очевидно, всегда многословны. Если вам случается знать ответ на заглавный вопрос, не стесняйтесь просто ответить на него, не читая мою расширенную дискуссию ниже.
Класс 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
значениями (или, точнее, мне приходится писать перегруженные версии вышеуказанных методов для каждого типа I) хочу поддержать). Почему я не могу это сделать?
// 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>
, очевидно, имеет ограничение where T : class
, а Я не понимаю, почему . Я имею в виду, , может быть , потому что уже существуют перегрузки для CompareExchange
, которые принимают Int32
, Int64
, Double
и т. Д .; но это вряд ли кажется хорошим обоснованием. В моем случае, например, было бы очень удобно иметь возможность использовать метод Aggregate<T>
для выполнения широкого спектра атомных расчетов.