【问题标题】:C++11: GCC 4.8 static thread_local std::unique_ptr undefined referenceC++11:GCC 4.8 静态 thread_local std::unique_ptr 未定义参考
【发布时间】:2013-10-17 16:47:04
【问题描述】:

我需要为将通过宏访问的每个线程存储一个唯一指针。我想我应该用一个单例和静态 thread_local std::unique_ptr 对象来解决这个问题。这是代码的简化版本:

main.cpp

#include <thread>
#include <vector>
#include <iostream>
#include <mutex>
using namespace std;

#include "yay.hpp"

mutex coutMutex;

void yay(int id)
{
    int* yayPtr = getYay();

    // I know this is bad
    coutMutex.lock();
    cout << "Yay nr. " << id << " address: " << yayPtr << endl;
    coutMutex.unlock();
}

int main()
{
    vector<thread> happy;
    for(int i = 0; i < thread::hardware_concurrency(); i++)
    {
        happy.push_back(thread(yay, i));
    }

    for(auto& smile : happy)
    {
        smile.join();
    }
    return 0;
}

耶.hpp

#ifndef BE_HAPPY
#define BE_HAPPY

#include <memory>
class Yay
{
    private:
        static thread_local std::unique_ptr<int> yay;
        Yay() = delete;
        Yay(const Yay&) = delete;
        ~Yay() {}
    public:
        static int* getYay()
        {
            if(!yay.get())
            {
                yay.reset(new int);
            }
            return yay.get();
        }
};

#define getYay() Yay::getYay()

#endif

yay.cpp

#include "yay.hpp"

thread_local std::unique_ptr<int>  Yay::yay = nullptr;

如果我用 gcc 4.8.1 编译它:

g++ -std=c++11 -pthread -o yay main.cpp yay.cpp

我明白了:

/tmp/cceSigGT.o: In function `_ZTWN3Yay3yayE':
main.cpp:(.text._ZTWN3Yay3yayE[_ZTWN3Yay3yayE]+0x5): undefined reference to `_ZTHN3Yay3yayE'
collect2: error: ld returned 1 exit status

我希望我可以从 clang 获得更多信息,但是它与 clang 3.4 完美配合:

clang++ -std=c++11 -pthread -o yay main.cpp yay.cpp

运行程序会产生我期望的结果:

Yay nr. 2 address: 0x7fcd780008e0
Yay nr. 0 address: 0x7fcd880008e0
Yay nr. 1 address: 0x7fcd800008e0
Yay nr. 3 address: 0x7fcd700008e0
Yay nr. 4 address: 0x7fcd740008e0
Yay nr. 5 address: 0x7fcd680008e0
Yay nr. 6 address: 0x7fcd6c0008e0
Yay nr. 7 address: 0x7fcd600008e0

我不确定我在这里做错了什么,不可能有静态 thread_local unique_ptr 对象吗?它适用于简单类型,如 int 或“裸”指针。

编辑:

这可能是与http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55800相关的错误

编辑2:

解决方法 1:使用 clang (yay.cpp) 编译一个文件

解决方法2(可怕且不可移植):首先将yay.cpp编译为程序集,添加

.globl _ZTWN3Yay3yayE
_ZTWN3Yay3yayE = __tls_init

到汇编文件,编译到目标文件,与其余部分链接

【问题讨论】:

  • getYay() 的预处理器替换有可能把你搞砸了吗?
  • 不,如果我删除#define 并直接调用 Yay::getYay() 将不起作用。
  • 在您的错误报告中,您显示了一个大大简化的代码版本和一个可能的解决方法。也许您可以将其发布为答案。
  • 我不知道 - “解决方法”只是在弄乱程序集输出。正确的解决方案是弄乱生成程序集并发送补丁的内容。但是,我对 gcc 的了解还不够。但我想我会用解决方法编辑帖子
  • GCC 4.8 已经过时,它的 C++11 支持不完整。

标签: c++ gcc c++11 clang thread-local-storage


【解决方案1】:

我通过在 Yay.hpp 中为 Yay 定义一个无操作的 ctor 来进行实验:

- 耶()=删除; +耶(){}

当我这样做时,错误消息变为:

/tmp/cc8gDxIg.o:在函数“Yay::yay 的 TLS 包装函数”中: main.cpp:(.text._ZTWN3Yay3yayE[_ZTWN3Yay3yayE]+0x5): 未定义对“Yay::yay 的 TLS 初始化函数”的引用

这让我找到了GCC bug 55800。该错误存在于 4.8.2 之前的 GCC 版本中,并在 4.8.3 和 4.9 中得到修复。在我在重复的GCC bug 59364 上找到的讨论线程中,已决定不支持修复。因此,在您迁移到 4.9 之前,您的汇编程序破解似乎是唯一可用的解决方案。

【讨论】:

    【解决方案2】:

    对我来说,原来我正在与-Wl,--image-base,0x14000000 链接并将其删除或将其更改为-Wl,--image-base,0x10000000,问题就消失了。不知道这里到底发生了什么......

    我相信我遇到了 gcc 错误64697,因为它确实是一个静态 thread_local -std=c++11。它工作在 32 位,但不是 64?很奇怪……gcc 8.2.0 mingw w64 交叉编译:

     librtmfp.a(IOSocket.o):IOSocket.cpp:(.text+0x46c4): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `TLS init function for Base::ThreadQueue::_PCurrent'
    

    原提示here

    【讨论】:

      猜你喜欢
      • 2014-10-26
      • 1970-01-01
      • 2014-05-12
      • 2018-01-24
      • 1970-01-01
      • 1970-01-01
      • 2018-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多