8

在 C 中,在全局范围内声明一个静态变量使其成为全局变量。这个全局变量是线程间共享的还是每个线程分配的?

更新:如果它们在线程之间共享,那么在线程/非共享的预先存在的库中创建全局变量的简单方法是什么?

Update2:基本上,我需要以线程安全的方式使用预先存在的 C 库和全局变量。

4

3 回答 3

19

它对整个进程(即所有线程)都是可见的。当然,这是在实践中。从理论上讲,您不能说因为线程与 C 标准无关(至少到 c99,这是在提出这个问题时生效的标准)。

但是我曾经使用过的所有线程库都具有可供所有线程访问的全局变量。


更新1:

许多线程库(例如 pthreads)将允许您创建特定于线程的数据,这是函数创建和使用特定于线程的数据而无需通过函数传递的一种方法。

因此,例如,返回伪随机数的函数可能希望每个线程都有一个独立的种子。因此,每次调用它时,它都会创建或附加到持有该种子的特定于线程的块(使用某种密钥)。

这允许函数保持与非线程函数相同的签名(例如,如果它们是 ISO C 函数则很重要),因为其他解决方案涉及向函数调用本身添加线程特定的指针。

另一种可能性是拥有一组全局变量,每个线程都有一个全局变量,例如:

int fDone[10];
int idx;
: : :
for (i = 0; i < 10; i++) {
    idx = i;
    startThread (function, i);
    while (idx >= 0)
        yield();
}

void function () {
    int myIdx = idx;
    idx = -1;
    while (1) {
        : : :
    }
}

这将允许线程函数被告知数组中的哪个全局变量属于它。

毫无疑问,还有其他方法,但由于不了解您的目标环境,因此讨论它们没有多大意义。


更新 2:

在线程环境中使用非线程安全库的最简单方法是为包装器调用提供互斥保护

例如,假设您的库具有非线程安全doThis()功能。您所做的是为它提供一个包装器:

void myDoThis (a, b) {
    static mutex_t serialize;
    mutex_claim (&serialize);
    doThis (a, b);
    mutex_release (&serialize);
}

将会发生的情况是,一次只有一个线程能够声明互斥锁(并因此调用非线程安全函数)。其他人将被阻止,直到当前的人返回。

于 2009-08-27T04:30:38.813 回答
1

C/C++ 标准不支持线程。所以所有变量在线程之间共享。在 C/C++ 运行时库中实现的线程支持不是标准的一部分。运行时特定于 C/C++ 的每个实现。如果你想用 C++ 编写可移植的代码,你可以使用boost interprocess library

要在 Microsoft Visual Studio 中声明线程局部变量,您可以使用 Microsoft 特定关键字__declspec( thread )

于 2009-08-27T04:34:15.110 回答
1

正如@Pax 提到的,静态变量对所有线程都是可见的。没有与特定线程关联的 C++ 数据结构。

但是,在 Windows 上,您可以使用TlsAlloc API 为特定于线程的数据分配索引并将该索引放入静态变量中。每个线程都有自己的槽,您可以使用此索引以及 TlsGetValue 和 TlsSetValue 访问它。有关更多信息,请阅读MSDN 上的使用线程本地存储

更新:没有办法使预先存在的库中的全局变量是线程特定的。任何解决方案都需要您修改代码以了解数据具有线程关联性。

于 2009-08-27T04:35:56.167 回答