Tuyên bố miễn trừ trách nhiệm: Bài đăng của tôi dường như luôn dài dòng. Nếu bạn biết câu trả lời cho câu hỏi tiêu đề, vui lòng chỉ trả lời câu hỏi mà không đọc thảo luận mở rộng của tôi bên dưới.Tại sao Interlocked.CompareExchange <T> chỉ hỗ trợ các loại tham chiếu?
Lớp System.Threading.Interlocked
cung cấp một số phương pháp rất hữu ích để hỗ trợ cho việc viết mã thread-safe. Một trong những phương pháp phức tạp hơn là CompareExchange
, có thể được sử dụng để tính toán tổng số đang chạy có thể được cập nhật từ nhiều luồng.
Kể từ khi việc sử dụng các CompareExchange
là một chút khó khăn, tôi nghĩ rằng nó là một ý tưởng khá phổ biến-tinh thần để cung cấp một số phương pháp helper cho nó:
// 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; });
}
Bây giờ, có lẽ tôi chỉ có tội là generic-hạnh phúc (Tôi sẽ thừa nhận, điều này thường đúng); nhưng nó cảm thấy ngớ ngẩn với tôi để hạn chế chức năng được cung cấp bởi các phương pháp trên chỉ với giá trị double
(hoặc, chính xác hơn, đối với tôi phải viết các phiên bản quá tải của các phương pháp trên cho mọi loại tôi muốn hỗ trợ). Tại sao tôi không thể làm điều này?
// 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)
)
);
}
tôi không thể làm điều này vì Interlocked.CompareExchange<T>
dường như có một hạn chế where T : class
, và Tôi không hiểu tại sao. Ý tôi là, có lẽ đó là do đã quá tải cho CompareExchange
chấp nhận Int32
, Int64
, Double
, v.v ...; nhưng điều đó hầu như không có lý do chính đáng. Trong trường hợp của tôi, ví dụ, nó sẽ khá tiện dụng để có thể sử dụng phương pháp Aggregate<T>
để thực hiện một loạt các tính toán nguyên tử.
Tôi nghĩ rằng điều này tập trung vào tôi một khi tôi đọc điều này trong tài liệu MSDN ngay sau khi đăng câu hỏi (cho quá tải chấp nhận tham số 'Object'):" Các đối tượng được so sánh cho bình đẳng tham chiếu, thay vì 'Object.Equals' Kết quả là, hai trường hợp đóng hộp cùng loại giá trị (ví dụ, số nguyên 3) luôn xuất hiện là không bằng nhau và không có thao tác nào được thực hiện. Không sử dụng quá tải này với các kiểu giá trị. " Tất nhiên - nó sẽ không sử dụng phương thức 'Equals', mà là tự kiểm tra các tham chiếu. –
Vì vậy, rõ ràng sự lựa chọn duy nhất của tôi thực ra là viết tất cả những phương thức quá tải đó (cho 'int',' long', vv) sau tất cả - nếu tôi thực sự muốn đi theo con đường đó. Đúng? –
@Dan: Tôi không chắc chắn làm thế nào bạn sẽ làm điều đó cho một loại giá trị lớn hơn * nguyên tử * mà không sử dụng một 'khóa' (hoán đổi một loạt các giá trị số nguyên). Điểm trao đổi so sánh là nó là nguyên tử; nghĩa là, sẽ không có một thời điểm nào khi bạn có thể quan sát một phần của hoạt động được thực hiện và phần kia thì không. Đặt một loạt các trao đổi so sánh với nhau sẽ không giúp làm cho nguyên tử hoạt động tổng thể (mỗi phần là nguyên tử, nhưng toàn bộ hoạt động, không phải là). –