2015-09-03 4 views
4

Почему 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; 
}; 
  1. Почему может thread_local не применяется к не-статические данные? Что такое является обоснованием этого ограничения? Разве я не дал хороший пример , где поточно-локальные нестатические элементы данных делают совершенным смысл?
  2. Что представляют собой лучшие практики для реализации элементов данных, связанных с потоком-нестационарным ?

ответ

4

Что касается причины, почему thread_local не может применяться к нестационарным элементам данных, это нарушит обычную гарантию заказа таких членов. То есть, члены данных в пределах одной группы public/private/protected должны быть выложены в памяти в том же порядке, что и в объявлении класса. Не говоря уже о том, что произойдет, если вы выделите класс в стеке - члены TLS не будут входить в стек.

Что касается этого, предлагаю использовать boost::thread_specific_ptr. Вы можете поместить один из них в свой класс и получить нужное поведение.

2

Таким образом, что поток локального хранения обычно работает в том, что вы получаете ровно один указатель в нить определенной структуры данных (например, TEB in Windows

Пока все нити локальные переменные являются статическими, компилятор может легко вычислить размер эти поля выделяют структуру размера и назначают статическое смещение в эту структуру для каждого поля.

Как только вы разрешаете нестатические поля, вся эта схема становится более сложной - один из способов ее решения будет одним из дополнительных уровень косвенности и сохранение индекса в каждом классе (теперь у вас есть скрытые поля в классах, довольно неожиданно).

Вместо того, чтобы поднимать сложность такой схемы на исполнителе, они, по-видимому, решили разрешить каждому приложению иметь дело с ней по необходимости.

 Смежные вопросы

  • Нет связанных вопросов^_^