【发布时间】:2015-03-04 10:55:35
【问题描述】:
我尝试在 C++ 中实现一个非常基本的 Thread Local Singleton 类——它是一个模板类,其他类随后继承自该类。问题是它几乎总是有效,但时不时地(比如 15 次运行 1 次),它会失败并出现如下错误:
* 检测到 glibc * ./myExe: free(): invalid next size (fast): 0x00002b61a40008c0 ***
请原谅下面这个相当做作的例子,但它可以说明问题。
#include <thread>
#include <atomic>
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
template<class T>
class ThreadLocalSingleton
{
public:
/// Return a reference to an instance of the object
static T& instance();
typedef unique_ptr<T> UPtr;
protected:
ThreadLocalSingleton() {}
ThreadLocalSingleton(ThreadLocalSingleton const&);
void operator=(ThreadLocalSingleton const&);
};
template<class T>
T& ThreadLocalSingleton<T>::instance()
{
thread_local T m_instance;
return m_instance;
}
// Create two atomic variables to keep track of the number of times the
// TLS class is created and accessed.
atomic<size_t> creationCount(0);
atomic<size_t> accessCount(0);
// Very simple class which derives from TLS
class MyClass : public ThreadLocalSingleton<MyClass>
{
friend class ThreadLocalSingleton<MyClass>;
public:
MyClass()
{
++creationCount;
}
string getType() const
{
++accessCount;
return "MyClass";
}
};
int main(int,char**)
{
vector<thread> threads;
vector<string> results;
threads.emplace_back([&]() { results.emplace_back(MyClass::instance().getType()); MyClass::instance().getType(); });
threads.emplace_back([&]() { results.emplace_back(MyClass::instance().getType()); MyClass::instance().getType(); });
threads.emplace_back([&]() { results.emplace_back(MyClass::instance().getType()); MyClass::instance().getType(); });
threads.emplace_back([&]() { results.emplace_back(MyClass::instance().getType()); MyClass::instance().getType(); });
for (auto& t : threads)
{
t.join();
}
// Expecting 4 creations and 8 accesses.
cout << "CreationCount: " << creationCount << " AccessCount: " << accessCount << endl;
}
我可以使用 build 命令在 coliru 上复制它: g++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
非常感谢!
【问题讨论】:
-
您可能同时修改了
results。 -
单例的实现看起来基本没问题(
thread_local暗示 static, andstatic` 局部变量保证被初始化为线程安全的)。不能说同时访问vector。虽然关于单例,我想知道首先需要一个线程本地单例(它是一个单例,还是每个线程有一个?)我宁愿=delete复制构造函数和赋值运算符。 -
当然,这是最有可能的问题,emplace_back 不是线程安全的。我会检查修复是否会增加可靠性。谢谢大家:)
标签: c++ multithreading c++11 thread-local-storage