переменная thread_local не согласована в потоке - PullRequest
3 голосов
/ 07 октября 2019

У меня есть переменная в файле tracker.hpp:

namespace TRIALS
{
    static thread_local int a = -1;
}

У меня есть другой класс в файле с именем EMP в ema.hpp / ema.cpp

namespace Algo
{
    class EMP
    {
        public:
            void Sample();
    };
}
namespace Algo
{
    void EMP::Sample()
    {
        std::cout << "model " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;
    }
}

Тогда мой основной файл у меня есть


auto model = Algo::EMP();

void Simulate(const int a)
{
    TRIALS::a = a;
    model.Sample()
    std::cout << "worker " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;
}

int main()
{
    std::cout << &TRIALS::a << std::endl;
    const int nthreads = 1;

    std::cout << "main " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;

    std::vector<std::thread> threads;
    for(int i=0; i<nthreads; ++i)
    {
        threads.emplace_back(&Simulate, i);
    }

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

    std::cout << "main " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;

    return 0;
}

Я просто запускаю один поток для отладки, но это вывод:

0x7f9540b621d8

main 140279012532800 0x7f9540b621d8 -1 (как и ожидалось)

модель 140278985606912 0x7f953f1b469c -1 (Разве это не должно быть 0 ??)

работник 140278985606912 0x7f953f1b4698 0 (как и ожидалось)

основной 140279012532800 0x7f95b (как ожидается)

У меня сложилось впечатление, что у каждого потока есть собственная локальная копия TRIALS :: a. Модель a in корректно увеличивается, но когда она возвращается из функции в том же потоке, значение по-прежнему равно 0. Я распечатываю идентификаторы потоков и адрес a для хорошей меры, и я вижу, что на самом деле есть 3 различныхверсии TRIALS :: a, несмотря на всего две темы.

В качестве дополнительного вопроса, в чем разница между static thread_local int a и thread_local int a?

1 Ответ

3 голосов
/ 07 октября 2019

В вашем примере static заставляет этот объект thread_local использовать внутреннюю связь, так что у каждого модуля перевода (файла .cpp) есть собственная копия переменной.

См. спецификаторы класса хранения для подробностей:

Ключевое слово thread_local разрешено только для объектов, объявленных в области пространства имен, объектов, объявленных в области блока, и статических членов данных. Это указывает на то, что объект имеет длительность хранения потока. Его можно комбинировать с static или extern, чтобы указать внутреннюю или внешнюю связь (за исключением элементов статических данных, которые всегда имеют внешнюю связь), соответственно, но эта дополнительная статика не влияет на продолжительность хранения.

Т.е. вы можете удалить это ключевое слово static, чтобы у вас была только одна копия объекта во всем приложении. В заголовочном файле выполните:

namespace TRIALS {
    extern thread_local int a;
}

И в одном из .cpp:

thread_local int TRIALS::a = -1;

В C ++ 17 вы можете сделать переменную inline, чтобы избежатьпредоставить свое определение в .cpp:

namespace TRIALS {
    inline thread_local int a = -1;
}
...