C ++ 11: GCC 4.8 static thread_local std :: unique_ptr неопределенная ссылка

Мне нужно хранить уникальный указатель для каждого потока, который будет доступен через макрос. Я подумал, что должен решить эту проблему с помощью одноэлементных и статических объектов thread_local std :: unique_ptr. Вот упрощенная версия кода:

#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;
}
#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
#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

Обходной путь 1: скомпилируйте один файл с помощью clang (yay.cpp)

Обходной путь 2 (ужасный и непереносимый): сначала скомпилируйте yay.cpp в сборку, добавьте

.globl _ZTWN3Yay3yayE
_ZTWN3Yay3yayE = __tls_init

в файл сборки, скомпилировать в объектный файл, связать с остальным

14

Решение

Я экспериментировал с этим, определяя ctor бездействия для Yay в Yay.hpp:

- Yay () = удалить;
+ Yay () {}

Когда я сделал это, сообщение об ошибке стало:

/tmp/cc8gDxIg.o: В функции `Функция-обертка TLS для Yay :: yay ':
main.cpp :(. text._ZTWN3Yay3yayE [_ZTWN3Yay3yayE] + 0x5): неопределенная ссылка на `функцию инициализации TLS для Yay :: yay '

Это привело меня к Ошибка GCC 55800. Ошибка существует в версиях GCC до 4.8.2 и исправлена ​​в 4.8.3 и 4.9. В обсуждении темы я нашел на дубликате Ошибка GCC 59364, было принято решение не портить исправление. Таким образом, ваш хакерский ассемблер, кажется, является единственным доступным решением, пока вы не перейдете на 4.9.

3

Другие решения

Для меня оказалось, что я связываюсь с -Wl,--image-base,0x14000000 и удалив это или изменив его на -Wl,--image-base,0x10000000 и проблема ушла. Понятия не имею, что на самом деле здесь происходит …

Я полагаю, что столкнулся с gcc bug 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'

Оригинальная подсказка Вот.

0

По вопросам рекламы [email protected]