Я использую собственную реализацию сопрограмм на 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 вместо своих собственных. Это потому, что доступ к локальной переменной потока делает следующее:
- Найдите указатель потока TLS для текущего потока.
- Добавьте смещение TLS x к указателю потока
- Используйте память по этому адресу как x
Однако при включенной оптимизации (1) и, возможно, (2) оптимизируются для второго доступа, поскольку компилятор предполагает, что функция, которая начинает выполняться в определенном потоке, останется в этом потоке. Это предположение неверно для моего кода.
Как я могу заставить компилятор смотреть на правильное локальное хранилище потока как до, так и после вызова move_to_thread, не отказываясь полностью от оптимизации?