Я попытался реализовать очень простой текстовый класс Local Singleton в C++ - это класс шаблонов, который наследуют другие классы. Проблема заключается в том, что он почти всегда работает, но и теперь каждый раз (скажем, 1 работать в 15), она не будет выполнена с ошибкой вдоль линий:C++ Thread Локальный одноточечный прерывистый сбой
* GLibC обнаружен * ./myExe: бесплатно (): недопустимый следующий размер (быстрый): 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;
}
Я могу повторить это на coliru, используя команду сборки: г ++ -std = C++ 11 -O2 -Wall -pedantic -pthread main.cpp & & ./a.out
Большое спасибо!
Возможно, у вас есть одновременная модификация «результатов». – molbdnilo
Реализация синглтона как такового кажется в основном ОК ('thread_local' подразумевает static', а' static' locals гарантированно инициализируются поточно-безопасными). Что нельзя сказать о доступе к «вектору» одновременно. Хотя об одном синглете интересно, зачем нужен ниток-локальный синглтон в первую очередь (либо это одноэлемент, либо один в потоке?), И я предпочел бы '= delete' конструктор копирования и оператор присваивания. – Damon
Конечно, это наиболее вероятная проблема, emplace_back не является потокобезопасным. Я проверю, будет ли исправление, повышающее надежность. Спасибо, парни :) – DaveM