Как заставить g ++ в Linux обновить указатель потока (для TLS), когда сопрограмма переключает потоки?

Я использую пользовательскую реализацию сопрограмм в C ++ (компилятор g ++, на ARM). Сопрограммы могут мигрировать из одного потока в другой, вызывая функцию move_to_thread (или другими способами, но это позволит мне высказать свое мнение). Я упрощаю, но это примерно так:

__thread int x = 0;

void f() {
x = 5;
// do some more work on current thread (thread 1, say)
move_to_thread(2);
// do more work, now on thread 2
int y = x; // with optimization, I'm getting the wrong x
}

У меня проблема в том, что работа, выполненная до и после вызова move_to_thread, использует локальные переменные потока (используя __thread). При компиляции с оптимизацией код, выполняющийся в потоке 2, по-прежнему получает доступ к локальным переменным потока 1 вместо своих собственных. Это потому, что доступ к локальной переменной потока делает следующее:

  1. Посмотрите на указатель потока TLS для текущего потока
  2. Добавьте смещение TLS в x к указателю потока
  3. Используйте память по этому адресу как х

Однако при включенной оптимизации (1) и, возможно, (2) оптимизируются для второго доступа, поскольку компилятор предполагает, что функция, которая начинает выполняться в определенном потоке, останется в этом потоке. Это предположение не верно для моего кода.

Как я могу заставить компилятор посмотреть на правильное локальное хранилище потока как до, так и после вызова move_to_thread, не покончив с оптимизацией полностью?

5

Решение

Что произойдет, если вы попытаетесь объявить свою переменную следующим образом:

__thread int volatile x = 0;

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

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]