我知道这个论坛已经讨论了很多。
但有一件事仍然让我感到困惑。
维基百科提到每个可重入代码都是线程安全的。
http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29
稍后给出一个可重入但不是线程安全的函数的示例。
int t;
void swap(int *x, int *y)
{
int s;
s = t; // save global variable
t = *x;
*x = *y;
// hardware interrupt might invoke isr() here!
*y = t;
t = s; // restore global variable
}
void isr()
{
int x = 1, y = 2;
swap(&x, &y);
}
这让我很困惑。所有可重入代码都是线程安全的吗?
此外,所有递归函数都是线程安全的。
我无法想象差异。
谢谢
最佳答案
重入和线程安全的概念是相关的,但不是等价的。您可以编写非线程安全的可重入函数和不可重入的线程安全函数。我将使用 C# 作为示例:
非线程安全的重入函数
此函数反转数组的条目:
void Reverse(int[] data) {
if (data == null || data.Length < 2) return;
for (var i = 0 ; i != data.Length/2 ; i++) {
int tmp = data[i];
data[i] = data[data.Length-i-1];
data[data.Length-i-1] = tmp;
}
}
这个函数显然是可重入的,因为它不引用外部资源。但是,它的线程安全性取决于不通过相同的
data
从多个线程。如果多个线程同时通过 Reverse
数组的相同实例,可能会产生不正确的结果。使这个函数无条件线程安全的一种方法是添加一个锁:void Reverse(int[] data) {
if (data == null || data.Length < 2) return;
lock (data) {
for (var i = 0 ; i != data.Length/2 ; i++) {
int tmp = data[i];
data[i] = data[data.Length-i-1];
data[data.Length-i-1] = tmp;
}
}
}
不可重入的线程安全函数
该函数调用函数
f()
c
次,并返回比其他值返回更多次的值。static int[] counts = new int[65536];
unsigned short MaxCount(Func<unsigned short> f, int c) {
lock(counts) {
Array.Clear(counts, 0, counts.Length);
for (var i = 0 ; i != c ; i++) {
counts[f()]++;
}
unsigned short res = 0;
for (var i = 1 ; i != counts.Length ; i++) {
if (counts[i] > counts[res]) {
res = i;
}
}
return res;
}
}
这个函数是线程安全的,因为它锁定了它用来进行计数的静态数组。但是,它不是可重入的:例如,如果仿函数
f
传入的是调用MaxCount
, 会返回错误的结果。
关于multithreading - 线程安全与重入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9441023/