thread_local in C++17
От: Videoman Россия https://hts.tv/
Дата: 01.02.23 08:53
Оценка:
Код вычистить пока не удалось, так что попробую пока своими словами. Появилась следующая проблема с thread_local объектом:
Если некий std::map, который объявлен как static в одном из С++ файлов. Также есть thread_local объект — регистратор, который всё что делает, в своём конструкторе регистрирует себя в static std::map, а в деструкторе разрегистрирует. Схема примерно такая:
[thread_local thread1_reg] --> [static std::map storage] <-- [thread_local thread2_reg]

В msvc- компилирует всё как задумано, вызывает конструкторы/деструкторы thread_local объекта в каждом потоке.
g++ и clang — вызывают конструктор/деструктор thread_local регистратора только для основного потока с main, во всех остальных потоках тишина.

У меня есть только одна догадка, что так как служебные потоки не обращаются непосредственно к thread_local объекту напрямую, а только к static мапе, линкеры выкидывают, по их мнению, не создающих внешнего эффекта конструкторы/деструкторы регистраторов.

Вопросы:
— прав ли я в своих догадках, или это что-то другое?
— как починить?
— может появилось что-то в С++17 для таких случаев, атрибуты там какие-нибудь или что-то похожее?

P.S. только что глянул ассебмлер: gcc реально создает объект в TLS только при первом обращении к thread_local объекту. Это так и должно быть? Можно ли как-то исхитрится и создавать объект как это делает "Студия", при запуске потока?
Отредактировано 01.02.2023 9:17 Videoman . Предыдущая версия .
Re: thread_local in C++17
От: rg45 СССР  
Дата: 01.02.23 09:26
Оценка:
Здравствуйте, Videoman, Вы писали:

V>У меня есть только одна догадка, что так как служебные потоки не обращаются непосредственно к thread_local объекту напрямую, а только к static мапе, линкеры выкидывают, по их мнению, не создающих внешнего эффекта конструкторы/деструкторы регистраторов.


А ты не рассматриваешь вариант, что это проделки линкера, а не компилера? Не может быть такого, что эти объекты определены в таких единицах трансляции в которых вообще нет никаких видимых связей с другими единицами трансляции и линкеры просто выкидывают весь объектник при линковке? Это тостаточно известная проблема, которая обсуждалась и на РСДН, давненько правда. Она имеет достаточно простое решение — в каком-нибудь общем заколовочном файле определяют константу какого-нибудь класса, а конструктор этого класса определяют в той самой единице трансляции, которую нужно форсированно прилинковать. Зачастую такие классы приходится делать фейковыми, если ничего реального нет под рукой.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: thread_local in C++17
От: Videoman Россия https://hts.tv/
Дата: 01.02.23 09:40
Оценка:
Здравствуйте, rg45, Вы писали:

R>А ты не рассматриваешь вариант, что это проделки линкера, а не компилера? Не может быть такого, что эти объекты определены в таких единицах трансляции в которых вообще нет никаких видимых связей с другими единицами трансляции и линкеры просто выкидывают весь объектник при линковке?


Не похоже, так как, thread_local объект объявляется в той же единицы трансляции что и static map в котором он регистрируется себя. thread_local конструктор вызывается главным потоком, не вызываются служебными. Кстати как я уже заметил, gcc вызывает конструктор thread_local объекта прямо перед первым обращением к нему, а такого обращения у меня нигде нет, т.к. я до этого предполагал, что thread_local подобен static объекту и взывает свой конструктор при старте потока, но оказывается это не так.

R>Это тостаточно известная проблема, которая обсуждалась и на РСДН, давненько правда. Она имеет достаточно простое решение — в каком-нибудь общем заколовочном файле определяют константу какого-нибудь класса, а конструктор этого класса определяют в той самой единице трансляции, которую нужно форсированно прилинковать. Зачастую такие классы приходится делать фейковыми, если ничего реального нет под рукой.


Вот эта техника у меня не работает с thread_local. Если нет к нему обращения именно в runtime из самого потока — объект в этом потоке не создается совсем. MSVC — делает по другому, логика похожа на static объекты.
Почему я решил спросить на форуме: во-первых уже много времени прошло, может стандарт как-то изменился в этом месте и можно с помощью атрибутов форсировать создание объекта
Re[3]: thread_local in C++17
От: rg45 СССР  
Дата: 01.02.23 09:46
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Вот эта техника у меня не работает с thread_local. Если нет к нему обращения именно в runtime из самого потока — объект в этом потоке не создается совсем. MSVC — делает по другому, логика похожа на static объекты.


Похоже на какую-то оптимизацию. А не пробовал добавить какую-нибудь искусственную зависимость — фейковую функцию-член, например, и как-то прикрутить ее вызов к основному потоку?

P.S. Хотя, это не интересно, наверное. Очевидно, что объект не может не создаться при таком сценарии. А для практического применения такой сценарий неприемлем.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 01.02.2023 9:56 rg45 . Предыдущая версия . Еще …
Отредактировано 01.02.2023 9:53 rg45 . Предыдущая версия .
Re: thread_local in C++17
От: vopl Россия  
Дата: 01.02.23 09:53
Оценка: 20 (2)
Здравствуйте, Videoman, Вы писали:

V>Код вычистить пока не удалось, так что попробую пока своими словами. Появилась следующая проблема с thread_local объектом:

V>Если некий std::map, который объявлен как static в одном из С++ файлов. Также есть thread_local объект — регистратор, который всё что делает, в своём конструкторе регистрирует себя в static std::map, а в деструкторе разрегистрирует. Схема примерно такая:
V>
V>[thread_local thread1_reg] --> [static std::map storage] <-- [thread_local thread2_reg]
V>

V>В msvc- компилирует всё как задумано, вызывает конструкторы/деструкторы thread_local объекта в каждом потоке.
V>g++ и clang — вызывают конструктор/деструктор thread_local регистратора только для основного потока с main, во всех остальных потоках тишина.

V>У меня есть только одна догадка, что так как служебные потоки не обращаются непосредственно к thread_local объекту напрямую, а только к static мапе, линкеры выкидывают, по их мнению, не создающих внешнего эффекта конструкторы/деструкторы регистраторов.


V>Вопросы:

V>- прав ли я в своих догадках, или это что-то другое?
V>- как починить?
V>- может появилось что-то в С++17 для таких случаев, атрибуты там какие-нибудь или что-то похожее?

V>P.S. только что глянул ассебмлер: gcc реально создает объект в TLS только при первом обращении к thread_local объекту. Это так и должно быть? Можно ли как-то исхитрится и создавать объект как это делает "Студия", при запуске потока?


Похоже, и ms и gcc/clang — оба ведут себя правильно.

https://timsong-cpp.github.io/cppwp/basic.stc.thread
thread_local определяет что место под объект выделяется в некоем стораже на каждый поток блабла
а инициализация объекта это отдельная песня. Судя по всему у тебя объект с нетривиальным конструктором, тогда это dynamic initialization

https://timsong-cpp.github.io/cppwp/basic.start.dynamic#7
реализация сама выбирает когда ей инициализировать такие объекты, то ли сразу то ли отложенно до первого odr-use. Судя по всему, ms делает сразу, а gcc/clang отложенно.

То есть, твоя догадка практически верна, любой odr-use в потоке требует наличия проинициализированного объекта, и компилятор это требование обеспечивает по факту odr-use

Как починить — хз, но плясать надо от того что надо как то сделать odr-use этого объекта в том потоке в котором он нужен.. Эта проблема несколько похожа на проблему динамических десериализаторов, у них из сети прилетают данные, из них десериализатор берет идентификатор и на его основе из мапы выбирает нужный процессор, далее отдает ему остаток данных. Вот их проблема — как сделать само-регистрирующийся в десериализаторе процессор. То есть, чтобы программист только написал код этого процессора, а он чик-чик сам бы в мапу записался. Там это решают на уровне static storage duration, а он инициализируется если есть побочные эффекты в конструкторе. Это легко обеспечить. В случае же thread_local внутренние побочные эффекты не учитываются для старта инициализации, нужно обязательно проявить активность снаружи объекта, сделать ему odr-use. И я так понимаю, что вариант явно ручками каждый такой thread_local потрогать в нужном потоке чтобы получилось odr-use — вовсе не вариант. Хз как это можно автоматизировать
Отредактировано 01.02.2023 13:50 vopl . Предыдущая версия . Еще …
Отредактировано 01.02.2023 9:57 vopl . Предыдущая версия .
Re[2]: thread_local in C++17
От: σ  
Дата: 01.02.23 10:05
Оценка:
V>https://timsong-cpp.github.io/cppwp/basic.start.dynamic#7
V>реализация сама выбирает когда ей инициализировать такие объекты, то ли сразу то ли отложенно до первого odr-use. Судя по всему, ms делает сразу, а gcc/clang отложенно.

Они вообще этого не делают, а не «отложенно»
Re[4]: thread_local in C++17
От: Videoman Россия https://hts.tv/
Дата: 01.02.23 10:06
Оценка:
Здравствуйте, rg45, Вы писали:

R>Похоже на какую-то оптимизацию. А не пробовал добавить какую-нибудь искусственную зависимость — фейковую функцию-член, например, и как-то прикрутить ее вызов к основному потоку?


Чего только не пробовал, не помогает. Только непосредственное обращение к объекту и именно в Runtime. Т.е. конструктор thread_local объекта получается никак не вызвать, если поток не обращается к объекту.
Дурость какая-то, перед каждым обращение к объекту вставляется безусловный вызов __tls_init() и внутри проверяется флаг и если уже вызывали, то проскакивает, если нет то вызывает конструктор. Вот ассемблер:
__tls_init():
0x000055555577a355  endbr64  
0x000055555577a359  push   %rbp 
0x000055555577a35a  mov    %rsp,%rbp 
0x000055555577a35d  movzbl %fs:0xffffffffffffffe0,%eax

0x000055555577a366  xor    $0x1,%eax 
0x000055555577a369  test   %al,%al 
0x000055555577a36b  je     0x55555577a3bf <__tls_init()+106> 

0x000055555577a36d  movb   $0x1,%fs:0xffffffffffffffe0 
0x000055555577a376  mov    %fs:0x0,%rax 
0x000055555577a37f  add    $0xffffffffffffffd0,%rax 
0x000055555577a385  lea    0x173434(%rip),%rdx        # 0x5555558ed7c0 <_ZN5htlib2v2L10g_queueMapE> 
0x000055555577a38c  mov    %rdx,%rsi 
0x000055555577a38f  mov    %rax,%rdi 
0x000055555577a392  call   0x55555577a238 <_ZN5htlib2v217SlotContextHolderC2ERNS0_12SlotQueueMapE> 
0x000055555577a397  mov    %fs:0x0,%rax 
0x000055555577a3a0  add    $0xffffffffffffffd0,%rax 
0x000055555577a3a6  lea    0x16fc5b(%rip),%rdx        # 0x5555558ea008 
0x000055555577a3ad  mov    %rax,%rsi 
0x000055555577a3b0  lea    -0xf7(%rip),%rax        # 0x55555577a2c0 <_ZN5htlib2v217SlotContextHolderD2Ev> 
0x000055555577a3b7  mov    %rax,%rdi 
0x000055555577a3ba  call   0x5555555704e0 <__cxa_thread_atexit@plt> 

0x000055555577a3bf  nop 

0x000055555577a3c0  pop    %rbp 
0x000055555577a3c1  ret
Re[3]: thread_local in C++17
От: vopl Россия  
Дата: 01.02.23 10:14
Оценка: +1
Здравствуйте, σ, Вы писали:

V>>https://timsong-cpp.github.io/cppwp/basic.start.dynamic#7

V>>реализация сама выбирает когда ей инициализировать такие объекты, то ли сразу то ли отложенно до первого odr-use. Судя по всему, ms делает сразу, а gcc/clang отложенно.

σ>Они вообще этого не делают, а не «отложенно»


Не вполне понял, чего они не делают вообще?
Инициализация отложена до первого odr-use. Думаю, и так понятно, что пока нет odr-use — нет и инициализации. Если odr-use нет никогда то и инициализации не будет никогда.
Re[2]: thread_local in C++17
От: Videoman Россия https://hts.tv/
Дата: 01.02.23 10:18
Оценка:
Здравствуйте, vopl, Вы писали:

V>...


V>То есть, твоя догадка практически верна, любой odr-use в потоке требует наличия проинициализированного объекта, и компилятор это требование обеспечивает по факту odr-use


V>Как починить — хз, но плясать надо от того что надо как то сделать odr-use этого объекта в том потоке в котором он нужен.. Эта проблема несколько похожа на проблему динамических десериализаторов, у них из сети прилетают данные, из них десериализатор берет идентификатор и на его основе из мапы выбирает нужный процессор, далее отдает ему остаток данных. Вот их проблема — как сделать само-регистрирующийся в десериализаторе процессор. То есть, чтобы программист только написал код этого процессора, а он чик-чик сам бы в мапу записался. Там это решают на уровне static storage duration, а он инициализируется если есть побочные эффекты в конструкторе. Это легко обеспечить. В случае же thread_local внутренние побочные эффекты не уситываются для старта инициализации, нужно обязательно проявить активность снаружи объекта, сделать ему odr-use. И я так понимаю, что вариант явно ручками каждый такой thread_local потрогать в нужном потоке чтобы получилось odr-use — вовсе не вариант. Хз как это можно автоматизировать


Точно! На практике именно это и видно. На самом деле у меня такая проблема:
Есть самописанные сигналы-слоты. Для вызова слотов в каждом потоке есть очередь. Мной предполагалось, что бы можно делать connect сигналов со слотами и опционально задавать bind к произвольному потоку, выбирая его очередь. Естественно очередь thread_local у каждого потока своя. Всё работало замечательно несколько лет, пока я не захотел вызвать connect сигнала в одном потоке, а дать bind слоту для другого. Предполагалось, что очередь там уже будет готова к моменту вызова. А вот оказалось, что пока запускаемый поток не тронет очередь, её физически не будет и сигналы летят в никуда.

Выход конечно есть. "Трогать" очередь слотов в нужном потоке и таким образом создавать её. Но это как-то криво, на мой взгляд. Потом у меня решение работало в общем виде, с любыми потоками, не обязательно моими, а теперь не знаю как выкрутится из этой ситуации.
Отредактировано 01.02.2023 10:21 Videoman . Предыдущая версия .
Re[3]: thread_local in C++17
От: vopl Россия  
Дата: 01.02.23 10:39
Оценка: 3 (1)
Здравствуйте, Videoman, Вы писали:

V>Здравствуйте, vopl, Вы писали:


V>>...


V>>То есть, твоя догадка практически верна, любой odr-use в потоке требует наличия проинициализированного объекта, и компилятор это требование обеспечивает по факту odr-use


V>>Как починить — хз, но плясать надо от того что надо как то сделать odr-use этого объекта в том потоке в котором он нужен.. Эта проблема несколько похожа на проблему динамических десериализаторов, у них из сети прилетают данные, из них десериализатор берет идентификатор и на его основе из мапы выбирает нужный процессор, далее отдает ему остаток данных. Вот их проблема — как сделать само-регистрирующийся в десериализаторе процессор. То есть, чтобы программист только написал код этого процессора, а он чик-чик сам бы в мапу записался. Там это решают на уровне static storage duration, а он инициализируется если есть побочные эффекты в конструкторе. Это легко обеспечить. В случае же thread_local внутренние побочные эффекты не уситываются для старта инициализации, нужно обязательно проявить активность снаружи объекта, сделать ему odr-use. И я так понимаю, что вариант явно ручками каждый такой thread_local потрогать в нужном потоке чтобы получилось odr-use — вовсе не вариант. Хз как это можно автоматизировать


V>Точно! На практике именно это и видно. На самом деле у меня такая проблема:

V>Есть самописанные сигналы-слоты. Для вызова слотов в каждом потоке есть очередь. Мной предполагалось, что бы можно делать connect сигналов со слотами и опционально задавать bind к произвольному потоку, выбирая его очередь. Естественно очередь thread_local у каждого потока своя. Всё работало замечательно несколько лет, пока я не захотел вызвать connect сигнала в одном потоке, а дать bind слоту для другого. Предполагалось, что очередь там уже будет готова к моменту вызова. А вот оказалось, что пока запускаемый поток не тронет очередь, её физически не будет и сигналы летят в никуда.

V>Выход конечно есть. "Трогать" очередь слотов в нужном потоке и таким образом создавать её. Но это как-то криво, на мой взгляд. Потом у меня решение работало в общем виде, с любыми потоками, не обязательно моими, а теперь не знаю как выкрутится из этой ситуации.


Кстати, обрати внимание, gcc/clang отрабатывают инициализацию таких thread_local не поштучно, а всей кагортой. То есть, достаточно тронуть один любой thread_local, и это приведет к инициализации всех thread_local для данного потока. Может этим можно как то сгладить кривизну? Типа завести один служебный thread_local "инициализатор" и при старте потока трогать только его, явно и специально. Но при этом держать в уме что это все implementation defined .
Re[4]: thread_local in C++17
От: σ  
Дата: 01.02.23 10:59
Оценка: 8 (1)
V>>>https://timsong-cpp.github.io/cppwp/basic.start.dynamic#7
V>>>реализация сама выбирает когда ей инициализировать такие объекты, то ли сразу то ли отложенно до первого odr-use. Судя по всему, ms делает сразу, а gcc/clang отложенно.

σ>>Они вообще этого не делают, а не «отложенно»


V>Не вполне понял, чего они не делают вообще?

V>Инициализация отложена до первого odr-use.

Нет. Если отложена, то не дальше, чем до первого odr-use. Может быть отложенной, но произойти раньше, чем первый odr-use. Обрати внимание на последнее предложение
> It is implementation-defined in which threads and at which points in the program such deferred dynamic initialization occurs.

V> Если odr-use нет никогда то и инициализации не будет никогда.


Из этого параграфа такого не следует.
Re[3]: thread_local in C++17
От: пффф  
Дата: 01.02.23 11:03
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Точно! На практике именно это и видно. На самом деле у меня такая проблема:

V>Есть самописанные сигналы-слоты. Для вызова слотов в каждом потоке есть очередь. Мной предполагалось, что бы можно делать connect сигналов со слотами и опционально задавать bind к произвольному потоку, выбирая его очередь. Естественно очередь thread_local у каждого потока своя. Всё работало замечательно несколько лет, пока я не захотел вызвать connect сигнала в одном потоке, а дать bind слоту для другого. Предполагалось, что очередь там уже будет готова к моменту вызова. А вот оказалось, что пока запускаемый поток не тронет очередь, её физически не будет и сигналы летят в никуда.

V>Выход конечно есть. "Трогать" очередь слотов в нужном потоке и таким образом создавать её. Но это как-то криво, на мой взгляд. Потом у меня решение работало в общем виде, с любыми потоками, не обязательно моими, а теперь не знаю как выкрутится из этой ситуации.


У тебя сигналы выбираются в потоке из своей очереди, и для них вызываются обработчики? Тогда, как я понимаю, в потоке должен быть какой-то message loop, не? По идее, там и нужно потрогать всё, что тебе нужно, не?

А как ты хочешь отправлять сигналы в чужие потоки, если там нет твоего message loop'а?
Re[5]: thread_local in C++17
От: vopl Россия  
Дата: 01.02.23 11:05
Оценка:
Здравствуйте, σ, Вы писали:

V>>>>https://timsong-cpp.github.io/cppwp/basic.start.dynamic#7

V>>>>реализация сама выбирает когда ей инициализировать такие объекты, то ли сразу то ли отложенно до первого odr-use. Судя по всему, ms делает сразу, а gcc/clang отложенно.

σ>>>Они вообще этого не делают, а не «отложенно»


V>>Не вполне понял, чего они не делают вообще?

V>>Инициализация отложена до первого odr-use.

σ>Нет. Если отложена, то не дальше, чем до первого odr-use. Может быть отложенной, но произойти раньше, чем первый odr-use. Обрати внимание на последнее предложение

>> It is implementation-defined in which threads and at which points in the program such deferred dynamic initialization occurs.

Точно точно! Там чуть ниже по треду я уже наткнулся именно на это, инициализация происходит раньше чем odr-use этого объекта (в частности, при odr-use другого thread_local объекта, но это не особо важно).

V>> Если odr-use нет никогда то и инициализации не будет никогда.


σ>Из этого параграфа такого не следует.


Согласен
Re[4]: thread_local in C++17
От: Videoman Россия https://hts.tv/
Дата: 01.02.23 11:10
Оценка:
Здравствуйте, vopl, Вы писали:

V>Кстати, обрати внимание, gcc/clang отрабатывают инициализацию таких thread_local не поштучно, а всей кагортой. То есть, достаточно тронуть один любой thread_local, и это приведет к инициализации всех thread_local для данного потока. Может этим можно как то сгладить кривизну? Типа завести один служебный thread_local "инициализатор" и при старте потока трогать только его, явно и специально. Но при этом держать в уме что это все implementation defined .


Да, я это заметил. При этом __tls_init все деструкторы объектов просаживает в __cxa_thread_atexit. Что бы тронуть что-то thread_lоcal в потоке, нужно это делать либо:
— Через свою обертку потока в начале — не хочется так как бывают другие потоки, например сторонние std::thread и не хочется завязывать свой thread на знания о каких-то там сигналах
— Через вызов где-то в потоке функции init_signals — не надежно, не красиво.

Получается, у меня только один путь, плясать не от потоков, а от слотов. В общей статической мапе хранить не ссылки на очереди слотов, а сами очереди с подсчетом ссылок на них. Как только происходит коннект сигнала к слоту, создавать очередь для потока, если её нет, а поток тогда уже путь берет ссылку на эту очередь когда готов вызвать свой loop. А от thread_local придется отказаться, а так хорошо дружили ...
Re[4]: thread_local in C++17
От: Videoman Россия https://hts.tv/
Дата: 01.02.23 11:18
Оценка:
Здравствуйте, пффф, Вы писали:

П>У тебя сигналы выбираются в потоке из своей очереди, и для них вызываются обработчики? Тогда, как я понимаю, в потоке должен быть какой-то message loop, не? По идее, там и нужно потрогать всё, что тебе нужно, не?


П>А как ты хочешь отправлять сигналы в чужие потоки, если там нет твоего message loop'а?


Всё так. Это все оптимизация краевых эффектов при инициализации. Представь создается объект и тут же вызывается его метод, который внутри себя использует сигналы. Внутри объекта создается служебный поток, которые дергает слоты в своём цикле. Нужно в промежутке между тем пока служебный поток не войдет в loop, не потерять вызовы снаружи объекта. Можно конечно не отпускать конструктор пока служебный поток не повиснет в цикле, но на практике это выльется в ручной синхронизации в каждом объекте построенном по такому принципу. Проще инкапсулировать всю логику в библиотечном классе.
Re[5]: thread_local in C++17
От: пффф  
Дата: 01.02.23 11:42
Оценка:
Здравствуйте, Videoman, Вы писали:

П>>А как ты хочешь отправлять сигналы в чужие потоки, если там нет твоего message loop'а?


V>Всё так. Это все оптимизация краевых эффектов при инициализации. Представь создается объект и тут же вызывается его метод, который внутри себя использует сигналы. Внутри объекта создается служебный поток, которые дергает слоты в своём цикле. Нужно в промежутке между тем пока служебный поток не войдет в loop, не потерять вызовы снаружи объекта. Можно конечно не отпускать конструктор пока служебный поток не повиснет в цикле, но на практике это выльется в ручной синхронизации в каждом объекте построенном по такому принципу. Проще инкапсулировать всю логику в библиотечном классе.


А, я понял. Но тут смотри какой нюанс. Без явной синхронизации всё равно есть какой-то момент, пусть и короткий, когда очередь в потоке ещё не инициализирована (дело не дошло до конструктора твоего thread_local объекта). Тебе просто везло (или может, проскакивало незамеченным) что у тебя ничего не терялось. Это косяк архитектуры
Re[6]: thread_local in C++17
От: Videoman Россия https://hts.tv/
Дата: 01.02.23 12:11
Оценка:
Здравствуйте, пффф, Вы писали:

П>А, я понял. Но тут смотри какой нюанс. Без явной синхронизации всё равно есть какой-то момент, пусть и короткий, когда очередь в потоке ещё не инициализирована (дело не дошло до конструктора твоего thread_local объекта). Тебе просто везло (или может, проскакивало незамеченным) что у тебя ничего не терялось. Это косяк архитектуры.


Не совсем. У меня просто в самом API не было возможности делать привязку к другому потоку, а можно было делать только к текущему. Поэтому, при первом же connect очередь и создавалась. Как только я расширил функционал, и захотел делать привязку к произвольному потому, то тут же и наступил на все вот эти грабли.
Re[5]: thread_local in C++17
От: AleksandrN Россия  
Дата: 01.02.23 13:43
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Всё так. Это все оптимизация краевых эффектов при инициализации.


Попробуй объявить как volatile. Может это отключит такую оптимизацию.
Re: thread_local in C++17
От: Sm0ke Россия ksi
Дата: 02.02.23 01:07
Оценка:
Здравствуйте, Videoman, Вы писали:

V>
V>[thread_local thread1_reg] --> [static std::map storage] <-- [thread_local thread2_reg]
V>


А если добавить не thread_local локальную переменную в начало функции потока, которая в конструкторе после лока мьютекса дёргает thread_local ?
Отредактировано 02.02.2023 1:07 Sm0ke . Предыдущая версия .
Re[2]: thread_local in C++17
От: Videoman Россия https://hts.tv/
Дата: 02.02.23 08:10
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>А если добавить не thread_local локальную переменную в начало функции потока, которая в конструкторе после лока мьютекса дёргает thread_local ?


То всё будет работать. Проблема в том, что у меня библиотека и не все возможные функции потока я контролирую. На самом деле проблему я решил — просто сделал свой аналог TLS, который работает по моим правилам.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.