И затем, я хочу использовать эту функцию в многопоточном коде, чтобы я мог изменить код следующим образом:
void foo(int i){
/* modify i */
}
Это, безусловно, не работает, так как вы будете изменять только копию i
.Вместо этого вам нужно будет передать int*
или int&
, если вы хотите, чтобы изменения не изменились.
Использование TLS, безусловно, не вызовет значительных накладных расходов (в пространстве или времени) по сравнению с любым пользовательским подходомможет следовать, чтобы реализовать ту же функциональность.Компиляторы на практике реализуют TLS, динамически выделяя «слот» хранилища в глобальной структуре данных, содержащей вашу локальную переменную потока.
Когда вы обращаетесь к локальной переменной потока во время выполнения, существует дополнительный уровень косвенностиСначала среда выполнения должна получить доступ к соответствующей таблице локальных переменных потока для текущего потока, а затем извлечь значение из таблицы.Эта выборка выполняется с использованием индекса в массив (который является операцией O (1)).
Если вы собираетесь сделать это:
__thread int i;
void foo(void){
int *p = &i;
/* modify i using p pointer */
}
, тогда нет необходимости обращаться кi
с помощью указателя.Думайте о i
как о глобальной переменной, которая имеет разные значения для каждого работающего потока.Вам не нужно было бы обращаться к обычному глобальному объекту через указатель, чтобы вносить изменения, поэтому также нет необходимости использовать указатель с локальной переменной потока.
Наконец, локальное хранение потока на самом деле не подразумевается.хранить большое количество переменных в потоке (существуют ограничения на размер таблицы TLS, зависящие от компилятора), но это то, что вы можете легко обойти: поместите множество переменных в struct
и сделайте указатель на struct
токарно-местный.