Эффективность кэширования со статическим членом в потоке - PullRequest
3 голосов
/ 30 апреля 2019

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

MainLoop()
{
    // ...

    SoundManager::PlaySound("sound1.mp3");  // Add a sound to be played, store the sound in a list in SoundManager
    SoundManager::PlaySound("sound2.mp3");
    SoundManager::PlaySound("sound3.mp3");

    // ...

    SoundThreadWorker.RunJob(); // Wake up thread and play every sound pushed in SoundManager

    // Running other threads

    SoundThreadWorker.WaitForFinish();  // Wait until the thread have finished its tasks, thread is put to sleep(but not closed)

    // Waiting other threads

    // ...
}

// In SoundThreadWorker class, running in a different thread from the main loop
RunJob()
{
    SoundManager::PlayAllSound();   // Play all sound stored in SoundManager
}

В этом случае статическая переменная, хранящая все звуки, должна быть безопасной, поскольку при работе потока звук не добавляется.

Эффективен ли этот кеш?

Я прочитал здесь, что: https://www.agner.org/optimize/optimizing_cpp.pdf

"Разные потоки нуждаются в отдельном хранилище. Нет функции или класса который используется несколькими потоками, должен полагаться на статический или глобальный переменные. (См. Локальное хранилище потоков, стр. 28). их стек. Это может привести к конфликтам в кэше, если потоки разделяют тот же кеш. "

Мне трудно понять, как статические переменные хранятся в кеше и как они используются каждым потоком. У меня есть два экземпляра SoundManager в кеше, так как поток не разделяет их стек? Нужно ли создавать общую память, чтобы избежать этой проблемы?

1 Ответ

2 голосов
/ 30 апреля 2019

Этот отрывок о памяти, которая меняется, а не о памяти, которая остается постоянной. Обмен констант между потоками - это нормально.

Если у вас есть несколько процессоров, каждый из которых обновляет одно и то же место, они должны постоянно посылать свои изменения назад и вперед друг другу. Это приводит к конфликту за «владение» определенным фрагментом памяти.

Часто право собственности не является явным. Но когда один процессор сообщает всем остальным, что определенная строка кэша должна быть аннулирована, потому что она просто что-то там изменила, тогда все остальные процессоры должны исключить значение из своих кэшей. Это приводит к тому, что процессор последний раз модифицирует часть памяти, эффективно «владея» строкой кеша, в которой он находился.

И, опять же, это проблема только того, что изменилось.

Кроме того, представление памяти и кеша, которое я вам дал, довольно упрощенное. Пожалуйста, не используйте его, рассуждая о безопасности потоков определенного фрагмента кода. Достаточно понять, почему несколько процессоров, обновляющих один и тот же кусок памяти, вредно для вашего кэша, но недостаточно для понимания того, какая версия процессора в определенной области памяти используется другими.

Местоположение памяти, которое не изменяется в течение времени жизни потока, используемого несколькими потоками, приведет к тому, что это место памяти появится в нескольких кэшах ЦП. Но это не проблема. Также это не проблема для конкретной области памяти, которая не изменяется, чтобы быть сохраненной в кэшах L2 и L3, которые являются общими для процессоров.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...