Я хочу смоделировать локальные переменные потока для нестатических членов, что-то вроде этого:
template< typename T, unsigned int tNumThread >
class ThreadLocal
{
private:
protected:
T mData[tNumThread];
unsigned int _getThreadIndex()
{
return ...; // i have a threadpool and each thread has an index from 0 to n
}
public:
ThreadLocal() {};
~ThreadLocal() {};
T& operator ->()
{
return mData[_getThreadIndex()];
}
...
};
Но проблема в том, что номер потока будет определен во время выполнения, и я должен выделить mData
из кучи.
Я хочу знать, есть ли способ не использовать выделение из кучи и использовать обычный массив, как указано выше?
Каждый поток имеет свой собственный стек, и помните, что кадры стека выталкиваются (или могут рассматриваться как выталкивающие), когда функция возвращается.
Вот почему у нас есть «Python без стеков», потому что 1 стек (что нужно Python) и несколько потоков не играют хорошо (см. Глобальную блокировку интерпретатора)
Вы можете поместить его в main, это будет длиться долго, но помните, что C (++) хочет знать все размеры в COMPILE TIME, поэтому, если число потоков изменяется (не фиксируется в COMPILE TIME), нет способа узнать это.
Что вам действительно нужно, так это что-то не основное, но это не шаблон (по числу), потому что это число не может быть известно во время компиляции.
Есть функция выделения стека (например, malloc), которую предоставляет GCC, но я не могу ее найти, хотя лучше избегать ее использования, потому что тогда оптимизации действительно работают.
Точно так же не стоит недооценивать возможности упреждающего чтения ваших процессоров и оптимизации GCC, если поместить массив в кучу, это неплохо.
Интересно читать с хорошими картинками, но, к сожалению, только отдаленно связанные с темой:
http://www.nongnu.org/avr-libc/user-manual/malloc.html
Я предлагаю:
std::unordered_map<std::thread::id, T, stackalloc> myTLS;
Либо вы заблокируете все доступы, либо подготовите популяцию заранее и получите доступ к ней только для чтения позже.
Вы можете использовать его в сочетании с распределителем стека.
typedef short_alloc<pair<const thread::id, T>, maxthrds> stackalloc;
https://howardhinnant.github.io/stack_alloc.html
Если вы хотите другое решение, здесь вы можете сделать:
struct Padder
{
T t;
char space_[128 - sizeof(T)]; // if sizeof(T) >= 128 just don't include the padding.
};
std::array<Padder, maxthreads> myTLS;
Для MESI доступ без узких мест.
С помощью этого метода вам нужно будет следить за тем, чтобы ваши потоки имели собственный индекс в этом массиве.