Почему thread_local
не применяется к нестационарным элементам данных? В принятом ответе на вопрос this question говорится: «Нет смысла создавать нестатические структуры или члены класса thread-local». Честно говоря, я вижу много веских причин, чтобы сделать нестатические члены данных нитями локальными.Почему thread_local не применяется к нестатическим членам данных и как реализовать поточно-локальные нестатические элементы данных?
Предположим, у нас есть какой-то ComputeEngine
с функцией-членом computeSomething
, которая называется много раз подряд. Некоторая часть работы внутри функции-члена может выполняться параллельно. Для этого каждый поток нуждается в некотором виде ComputeHelper
, который обеспечивает, например, вспомогательные структуры данных. Так что мы действительно хотим:
class ComputeEngine {
public:
int computeSomething(Args args) {
int sum = 0;
#pragma omp parallel for reduction(+:sum)
for (int i = 0; i < MAX; ++i) {
// ...
helper.xxx();
// ...
}
return sum;
}
private:
thread_local ComputeHelper helper;
};
К сожалению, этот код не компилируется. Что мы могли бы сделать вместо того, чтобы это:
class ComputeEngine {
public:
int computeSomething(Args args) {
int sum = 0;
#pragma omp parallel
{
ComputeHelper helper;
#pragma omp for reduction(+:sum)
for (int i = 0; i < MAX; ++i) {
// ...
helper.xxx();
// ...
}
}
return sum;
}
};
Однако это строительство и уничтожение ComputeHelper
между последовательными вызовами computeSomething
. Предполагая, что построение ComputeHelper
является дорогостоящим (например, из-за выделения и инициализации огромных векторов), мы можем захотеть повторно использовать ComputeHelper
s между последовательными вызовами. Это приводит меня к следующему шаблонного подхода:
class ComputeEngine {
struct ThreadLocalStorage {
ComputeHelper helper;
};
public:
int computeSomething(Args args) {
int sum = 0;
#pragma omp parallel
{
ComputeHelper &helper = tls[omp_get_thread_num()].helper;
#pragma omp for reduction(+:sum)
for (int i = 0; i < MAX; ++i) {
// ...
helper.xxx();
// ...
}
}
return sum;
}
private:
std::vector<ThreadLocalStorage> tls;
};
- Почему может
thread_local
не применяется к не-статические данные? Что такое является обоснованием этого ограничения? Разве я не дал хороший пример , где поточно-локальные нестатические элементы данных делают совершенным смысл? - Что представляют собой лучшие практики для реализации элементов данных, связанных с потоком-нестационарным ?