Подтвердить что ты не робот

Доступ к потоку-локальному из другого потока

Как я могу прочитать/написать локальную переменную потока из другого потока? То есть, в Thread A я хотел бы получить доступ к переменной в области локального хранилища нитей Thread B. Я знаю идентификатор другого потока.

Переменная объявляется как __thread в GCC. Целевая платформа - это Linux, но независимость может быть приятной (особенно для GCC).

Отсутствие крюка запуска нити не может просто отслеживать это значение в начале каждого потока. Все потоки должны отслеживаться таким образом (а не только специально запущенные).

Обертка более высокого уровня, такая как boost thread_local_storage или использование ключей pthread, не является опцией. Мне требуется производительность при использовании локальной переменной __thread.


ПЕРВЫЙ ОТВЕТ НЕПРАВИЛЬНО: нельзя использовать глобальные переменные для того, что я хочу делать. Каждый поток должен иметь свою собственную копию переменной. Кроме того, эти переменные должны быть __thread переменными по соображениям производительности (одинаково эффективное решение также будет в порядке, но я не знаю). Я также не контролирую точки ввода потока, поэтому нет возможности для этих потоков регистрировать любую структуру.


Thread Local не является приватным: другое недоразумение в отношении локальных переменных. Это никоим образом не какая-то частная переменная для потока. Они являются глобально адресуемой памятью, с ограничением, что их время жизни привязано к потоку. Любая функция из любого потока, если указана указатель на эти переменные, может их модифицировать. Вышеупомянутый вопрос касается, по сути, того, как получить этот адрес указателя.

4b9b3361

Ответ 1

Я, к сожалению, никогда не смог найти способ сделать это.

Без какого-либо хоста инициализации потока просто не появляется способ получить этот указатель (за исключением хакеров ASM, которые будут зависящими от платформы).

Ответ 2

Если вы хотите, чтобы локальные переменные потока, которые не являются потоковыми локальными, почему бы вам не использовать глобальные переменные?

Важное разъяснение!

Я не предлагаю, чтобы вы использовали один глобальный для замены локальной переменной. Я предлагаю использовать один глобальный массив или другой подходящий набор значений для замены одной локальной локальной переменной.

Вам нужно будет обеспечить синхронизацию, но, поскольку вы хотите выставить значение, измененное в потоке A, в поток B, не обойти это.

Update:

Документация GCC на __thread гласит:

Когда адрес-оператор применяется к локальной переменной потока, она оценивается во время выполнения и возвращается адрес текущего потока экземпляр этой переменной. Адрес полученный таким образом может использоваться любой нитью. Когда поток завершается, любые указатели к локальным переменным потока в этом нить становится недействительной.

Поэтому, если вы настаиваете на этом, я представляю себе возможность получить адрес локальной переменной потока из потока, к которому она принадлежит, сразу после того, как поток порожден. Затем вы можете сохранить указатель на эту ячейку памяти на карту (указатель потока id = > ) и позволить другим потокам обращаться к переменной таким образом. Это предполагает, что у вас есть код для порожденного потока.

Если вы действительно предприимчивы, вы можете попытаться выкопать информацию на ___tls_get_addr (начиная с этого PDF, что связано с вышеупомянутыми документами GCC). Но этот подход настолько высок для компилятора и платформы, что ему не хватает документации, что он должен вызывать тревоги в любой голове.

Ответ 3

Я ищу то же самое. Как я вижу, никто не ответил на ваш вопрос после поиска в Интернете во всех отношениях, я пришел к следующей информации: предположим, что для компиляции для gcc on linux (ubuntu) и использования -m64 регистр сегментов gs содержит значение 0. Скрытая часть сегмента (удерживающего линейный адрес) указывает на конкретную локальную область потока. Эта область содержит по этому адресу адрес этого адреса (64 бита). На более низких адресах хранятся все локальные переменные потока. Этот адрес - native_handle(). Поэтому, чтобы получить доступ к локальным данным потоков, вы должны сделать это с помощью этого указателя.

Другими словами: (char*)&variable-(char*)myThread.native_handle()+(char*)theOtherThread.native_handle()

Код, демонстрирующий вышеприведенные предположения g++, linux, pthreads:

#include <iostream>
#include <thread>
#include <sstream>

thread_local int B=0x11111111,A=0x22222222;

bool shouldContinue=false;

void code(){
    while(!shouldContinue);
    std::stringstream ss;
    ss<<" A:"<<A<<" B:"<<B<<std::endl;
    std::cout<<ss.str();
}

//#define ot(th,variable) 
//(*( (char*)&variable-(char*)(pthread_self())+(char*)(th.native_handle()) ))

int& ot(std::thread& th,int& v){
    auto p=pthread_self();
    intptr_t d=(intptr_t)&v-(intptr_t)p;
    return *(int*)((char*)th.native_handle()+d);
}

int main(int argc, char **argv)
{       

        std::thread th1(code),th2(code),th3(code),th4(code);

        ot(th1,A)=100;ot(th1,B)=110;
        ot(th2,A)=200;ot(th2,B)=210;
        ot(th3,A)=300;ot(th3,B)=310;
        ot(th4,A)=400;ot(th4,B)=410;

        shouldContinue=true;

        th1.join();
        th2.join();
        th3.join();
        th4.join();

    return 0;
}