C++ 线程本地单例间歇性失败

标签 c++ multithreading c++11 thread-local-storage

我尝试用 C++ 实现一个非常基本的 Thread Local Singleton 类——它是一个模板类,其他类可以从中继承。问题是它几乎总是有效,但时不时地(比如,15 次运行 1 次),它会失败并出现以下错误:

* 检测到 glibc * ./myExe: free(): 下一个大小无效(快速):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 上复制它: g++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out

非常感谢!

最佳答案

感谢 molbdnilo 和 Damon,他们很快指出了一个显而易见的事实 - vector::emplace_back 不是线程安全的,因此无法保证此代码是否实际工作。我已经将 main() 函数替换为以下内容,这似乎更可靠。

int main(int,char**)
{
    vector<thread> threads;
    vector<string> results;

    auto addToResult = [&results](const string& val)
    {
        static mutex m_mutex;
        unique_lock<mutex> lock(m_mutex);
        results.emplace_back(val);
    };

    threads.emplace_back([&addToResult]() { addToResult(MyClass::instance().getType()); MyClass::instance().getType(); });
    threads.emplace_back([&addToResult]() { addToResult(MyClass::instance().getType()); MyClass::instance().getType(); });
    threads.emplace_back([&addToResult]() { addToResult(MyClass::instance().getType()); MyClass::instance().getType(); });
    threads.emplace_back([&addToResult]() { addToResult(MyClass::instance().getType()); MyClass::instance().getType(); });

    for (auto& t : threads)
    {
        t.join();
    }

    // Expecting 4 creations and 8 accesses.
    cout << "CreationCount: " << creationCount << " AccessCount: " << accessCount << endl;
}

谢谢!

关于C++ 线程本地单例间歇性失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28852653/

相关文章:

c++ - 重载运算符。 Const 参数会产生一些问题

linux - epoll_wait() 无限返回 EINTR

.net - 多线程Random.NextDouble()

c++ - 使用 std::move 进行 vector 构建优化

c++ - 归档两个 .a 文件

c++ - 为什么int myVar {5}给出错误并且不起作用?

c++ - 使用 TinyCbor C 库编码和解码 uint8_t

c++ - 链接到使用 boost 库的静态库会导致 cmake 中出现链接错误

C++:覆盖纯虚拟成员变量?

multithreading - 并发 Haskell 异常