multithreading - 线程安全与重入

标签 multithreading operating-system

我知道这个论坛已经讨论了很多。
但有一件事仍然让我感到困惑。
维基百科提到每个可重入代码都是线程安全的。
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/

相关文章:

operating-system - 什么样的代码可以称为 "re-entrant"?

memory - 操作系统 - 匿名内存

c - 是否可以完全用 C 编写操作系统?

android - 如何使用暴力取消 AsyncTask

c++ - 像线程一样调用类方法

c++ - QThread 永远不会启动

c - 如何在 QNX 中重置进程 ID

performance - 计算每个线程的上下文切换

java - 如何在自己的线程中启动 JavaFX GUI

C++ POCO - 如何在不使用 run() 方法的情况下在线程池上启动线程?