Единственная интересная вещь, которую я извлек из небольшого изучения, это то, что MSVC работает иначе, чем clang/gcc.
Вот вывод MSVC для последнего компилятора:
Thread 34316 having counter value 1
Thread 34312 having counter value 1
Thread 34320 having counter value 1
Thread 34328 having counter value 1
Thread 34324 having counter value 1
Thread 34332 having counter value 1
Thread 34336 having counter value 1
Thread 34340 having counter value 1
Thread 34344 having counter value 1
Thread 34348 having counter value 1
Thread 29300 having counter value 0
c:\dv\TestCpp\out\build\x64-Debug (default)\TestCpp.exe (process 27748) exited with code 0.
Примечание. Поток 29300 имеет значение счетчика 0. Это основной поток. Поскольку doWork() никогда не вызывался в основном потоке, значение счетчика равно 0. Это работает так, как я ожидал, что все будет работать. c — это глобальный объект Counter — он должен создаваться во всех потоках, включая основной поток.
Однако, когда я запускаю (а godbolt, похоже, не любит запускать многопоточные программы, AFAICT) под clang и gcc с использованием rextester.com, я получаю:
Thread 140199006193408 having counter value 1
Thread 140198906181376 having counter value 1
Thread 140198806169344 having counter value 1
Thread 140198706157312 having counter value 1
Thread 140199106205440 having counter value 1
Thread 140199206217472 having counter value 1
Thread 140199306229504 having counter value 1
Thread 140199406241536 having counter value 1
Thread 140199506253568 having counter value 1
Thread 140199606265600 having counter value 1
Примечание. Нет основного потока со значением счетчика, равным 0. Объект c Counter никогда не создавался и не уничтожался в основном потоке в gcc и clang, однако он создавался и уничтожался в основном потоке в MSVC.
Я считаю, что ваша личная ошибка заключается в том, что вы используете старую версию компилятора, в которой есть ошибка. Я не мог воспроизвести вашу ошибку независимо от того, какую последнюю версию различных типов компиляторов я использовал, но я собираюсь сообщить об ошибке команде MSVC, потому что это стандартный C++, и, по одной из цифр, он должен давать одинаковые результаты независимо компилятора, и это не так.
Кажется (изучая https://en.cppreference.com/w/cpp/language/storage_duration), что MSVC может делать это неправильно, поскольку к объекту thread_local Counter c никогда не было явного доступа в основном потоке, и тем не менее объект был создан и уничтожен.
Посмотрим, что они скажут - у меня есть еще несколько ошибок, ожидающих их решения...
Дальнейшее исследование: справочная статья cpp, по-видимому, указывает на то, что, поскольку это чисто глобальный объект, то есть это не локальный объект статического потока, например:
Foo &
GetFooThreadSingleton()
{
static thread_local Foo foo;
return foo;
}
тогда я прочитал статью cppreference так: это глобальный, как и любой другой глобальный, и в этом случае MSVC делает это правильно. Кто-нибудь, пожалуйста, поправьте меня, если я ошибаюсь. Спасибо.
Кроме того, не запуская его изначально в Ubuntu внутри gdb и не проверяя, я не могу быть уверен, что глобальный объект на самом деле не был создан и уничтожен в основном потоке под gcc/clang, потому что могло случиться так, что мы просто пропустили этот вывод по какой-то причине. Я признаю, что это кажется маловероятным. Я попробую это позже, потому что этот вопрос меня немного заинтриговал.
Я запустил его изначально в Ubuntu и получил то, что ожидал: глобальный счетчик c создается и уничтожается только в том случае, если к нему обращаются в основном потоке. Итак, я думаю, что на данный момент это ошибка в gcc/clang.
person
David Bien
schedule
02.03.2021