Таблицы поиска в C++ 11 с многопоточностью

У меня есть 2 аналогичные ситуации в многопоточном программном обеспечении C++11:

  • массив, который я использую в качестве таблицы поиска внутри объявления метода
  • массив, который я использую в качестве таблицы поиска, объявленной вне метода, и которая используется разными и несколькими методами по ссылке или с указателями.

Теперь, если мы на минутку забудем об этих LUT и рассмотрим C++11 и многопоточный подход к универсальному методу, наиболее подходящим квалификатором для этих методов с точки зрения продолжительности хранения является, вероятно, thread_local,

Таким образом, если я кормлю метод foo() то есть thread_local в 3 потока я в основном в конечном итоге 3 экземпляра foo() для каждого потока этот ход "решает" проблему с foo() общий доступ и доступ к нему между 3 различными потоками, что позволяет избежать пропусков кэша, но у меня в принципе есть 3 возможных различных поведения для моего foo(), например, если у меня есть тот же PRNG, реализованный в foo(), и я предоставляю начальное число, зависящее от времени с действительно хорошим и высоким разрешением я, вероятно, получу 3 разных результата с каждым потоком и настоящий беспорядок с точки зрения согласованности.

Но скажем, что я в порядке с тем, как thread_local работает, как я могу записать тот факт, что мне нужно держать LUT всегда готовым и кэшированным для моих методов?

Я читал кое-что о смягченной или менее расслабленной модели памяти, но в C++11 я никогда не видел ни одного ключевого слова или практического приложения, которое могло бы внедрить кэширование массива /LUT .

Я на x86 или ARM.

Мне, вероятно, нужно что-то противоположное volatile в принципе.

2 ответа

Если LUT доступны только для чтения, поэтому вы можете поделиться ими без блокировок, вам следует просто использовать один из них (т.е. объявить их). static).

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

"Локальное хранилище потока" не означает, что память каким-то образом физически связана с потоком. Скорее, это способ позволить одному и тому же имени ссылаться на разные объекты в каждом потоке. Это никоим образом не ограничивает возможности любого потока для доступа к объекту, если ему дан его адрес.

Кэш процессора не программируется. Он использует собственную внутреннюю логику, чтобы определить, какие области памяти кэшировать. Как правило, он кэширует память, к которой только что обратился ЦП, или его логика прогнозирования определит, что ЦП вскоре получит к ней доступ. В многопроцессорной системе каждый ЦП может иметь свой собственный кеш, или разные ЦП могут совместно использовать кеш. Если имеется несколько кэшей, область памяти может кэшироваться более чем в одном одновременно.

Если все потоки должны видеть одинаковые значения в справочных таблицах, то лучше всего использовать одну таблицу. Это может быть достигнуто с помощью переменной с static срок хранения. Если данные могут быть изменены, то вам, вероятно, также понадобится std::mutex чтобы защитить доступ к таблице и избежать гонок данных. Данные только для чтения могут быть переданы без дополнительной синхронизации; в этом случае лучше всего это объявить const сделать явным только для чтения характер и избежать случайных изменений.

void foo(){
     static const int lut[]={...};
}

Ты используешь thread_local где каждый поток должен иметь свою собственную копию данных, обычно потому, что каждая копия будет изменена независимо. Например, вы можете использовать thread_local для вашего генератора случайных чисел, так что каждый поток имеет свой собственный ГСЧ, который не зависит от других потоков и не требует синхронизации.

void bar(){
    thread_local RandomNumberGenerator rng; // one per thread
    auto val=rng.nextRandomNumber(); // use the instance for the current thread
}
Другие вопросы по тегам