这两个代码段之间是否存在差异:
void f() {
thread_local vector<int> V;
V.clear();
... // use V as a temporary variable
}
Run Code Online (Sandbox Code Playgroud)
和
void f() {
static thread_local vector<int> V;
V.clear();
... // use V as a temporary variable
}
Run Code Online (Sandbox Code Playgroud)
Backstory:最初我有一个STATIC向量V(用于保存一些中间值,每次进入函数时都会被清除)和一个单线程程序.我想把程序变成多线程程序,所以我不得不摆脱这个静态修饰符.我的想法是将每个静态转换为thread_local并且不担心其他任何事情?这可能会适得其反吗?
在 Java 中,有时从不同线程访问相同变量时,每个线程都会创建自己的变量副本,因此如果我将一个线程中的变量值设置为10,然后我尝试从另一个线程,我不会得到10(因为第二个线程正在从变量的另一个副本中读取!)。
为了在 Java 中解决这个问题,我所要做的就是使用关键字 volatile,例如:
volatile int i = 123;
Run Code Online (Sandbox Code Playgroud)
C++中是否也存在这个问题?如果是这样,我该如何解决?
注意:我使用的是 Visual C++ 2010。
我现在试图通过研究实际的代码实现来了解 read(2) 函数的工作原理,首先,我尝试了解它是如何在 #include 头文件中定义的。
在该文件中,我发现了这个:
ssize_t read(int, void *, size_t) __DARWIN_ALIAS_C(read);
Run Code Online (Sandbox Code Playgroud)
然后,我用谷歌搜索找到了实际的 read() 函数声明。
和,
https://github.com/lattera/glibc/blob/master/io/read.c
我找到了这个。在这段代码中,
/* Read NBYTES into BUF from FD. Return the number read or -1. */
ssize_t
__libc_read (int fd, void *buf, size_t nbytes)
{
if (nbytes == 0)
return 0;
if (fd < 0)
{
__set_errno (EBADF);
return -1;
}
if (buf == NULL)
{
__set_errno (EINVAL);
return -1;
}
__set_errno (ENOSYS);
return -1;
}
Run Code Online (Sandbox Code Playgroud)
现在这是我的问题。
__libc_之前是什么read?为什么需要它?当用户调用read(2)时,如何调用这个函数?
在我看来,这段代码与从文件描述符读取缓冲区无关,而是只有处理可能的错误的代码: fd < …
有没有宣布任何优势std::vector的thread_local?喜欢
static unique_ptr<std::vector<ObjectA>> vecVariable;
Run Code Online (Sandbox Code Playgroud)
声明std::vector为thread_local不会使其操作像pop_back()和erase()同步.
由于在每一个STL容器,如果有一个线程修改的容器,然后应无并发线程读取或写入同一容器中,所以我不能做erase()和pop_back()一对vector在并行/多线程环境中的对象.
即使我将vector声明为thread_local,我的代码也会在其中一个操作中崩溃.我知道我可能需要在锁定下执行这些操作,但我只是想了解何时有人会定义std::vector为thread_local?
我最近使用了一个对象,其目的是将内存作为单例进行分配和释放。就像是
class MyValue
{
// ...
static Allocator& GetAllocator()
{
static Allocator allocator;
return allocator;
}
// ...
};
Run Code Online (Sandbox Code Playgroud)
后来我意识到它Allocator不是线程安全的:当多个线程同时使用同一个分配器时,偶尔会发生奇怪的事情,导致断言和分段错误。
解决方案:为不同的线程使用不同的分配器:
class MyValue
{
// ...
static Allocator& GetAllocator()
{
thread_local static Allocator allocator;
return allocator;
}
// ...
};
Run Code Online (Sandbox Code Playgroud)
惊人的!我的问题都消失了!只有一个问题: 每次创建线程时我的分配器变量都会被初始化,即使大多数线程不会使用该变量?
分配器的初始化可能是繁重的操作,因此我希望仅在实际需要时才对其进行初始化,而不是在每个线程中进行初始化。
我读到thread_local变量是由每个线程分配的。这是否意味着它们也是被构建的?这种分配(或构造)是针对创建的每个线程系统地发生还是仅针对使用它的线程发生?
我依稀记得在课程中听说过有关线程和线程本地存储的大多数细节都依赖于平台。如果是这样的话,我对 Linux 和 FreeBSD 特别感兴趣。
相关(有趣的读物,但我在那里找不到答案):
我想在一个线程内共享一个成员变量,但不在线程之间共享.
它的行为类似于静态成员,但它只是一个线程中的"全局",它是一个线程局部变量.
我可以想到两个解决方案:
首先,在每个线程中创建一个局部变量,然后将此变量作为参数传递给使用它的每个方法.(这会导致耦合)
或者,定义一个名为MyStruct的结构,其中包含一个线程局部变量和一个线程ID,然后将所有这些MyStructs作为一个向量,将此向量用作静态成员变量.
每次使用这个成员变量时,首先获取线程ID,然后找到具有相同线程ID的MyStruct,如果没有找到,则推回一个新的MyStruct.在线程结束之前删除此Mystruct.(这很不方便)
有简单的解决方案吗?