2017-01-14 3 views
3

Фактическая проблема заключается в том, что я пытаюсь отправить новый параметр в текущую нить. Идея заключалась в изменении переменной в потоке, которая не сработала. Код должен показать простой пример проблемы. Распечатка теста переменной должна быть 1 после обновления, но она всегда 0. Кто-нибудь понимает проблему и может помочь? Спасибо большое!Обновление переменной потока (C++)

#include <iostream> 
#include <thread> 

class MyThread { 
public: 
int test = 0; 
void operator()() const { 
    while (1) 
    std::cout << test << std::endl; 
} 
/* other public or private class members */ 
}; 

int main() { 
    MyThread mythread; 
    std::thread t(mythread); 
    mythread.test = 1; 
    t.join(); 
    return 0; 
} 
+0

Компилятор может видеть, что ваша тестовая переменная не изменяется в ходе метода, поэтому она хранится в регистре и пытается сделать ее изменчивой: volatile int test = 0; – Mehdi

+0

Это называется * расходом данных *. Ваш код имеет неопределенное поведение. Программирование с параллелизмом является тонким и требует большой осторожности. –

ответ

-3

На мой взгляд, вы должны объявить целочисленный элемент test в volatile.

volatile int test = 0; 

У вас есть 2 потока, которые обращаются к одной и той же переменной. Без объявления volatile компиляторы могут оптимизировать доступ к чтению/записи в памяти, что может привести к такому эффекту.

+0

Это неверно, поскольку не удается распознать проблемы когерентности кеша с многопоточными программами, работающими на многопроцессорных системах. Пожалуйста, прочитайте о барьерах памяти - https://en.wikipedia.org/wiki/Memory_barrier – marko

+0

Я полностью согласен с вашими упоминаемыми точками. Я просто хотел указать ** один аспект, чтобы реквестер понял сложность многопоточности. Правильный ответ, как уже упоминалось, «std :: atomic test;' –

+0

'volatile' - это решение почти ничего не происходит в наши дни на C и C++. Почти единственное место, где он по-прежнему имеет законное применение, - это драйверы устройств для относительно несложной встроенной системы. Там он используется, чтобы предотвратить оптимизацию вокруг чтения и записи в память, где они имеют нестандартную семантику (например, FIFO, регистры состояния с четким чтением и т. Д.). В более сложных случаях вы, вероятно, выделите доступ к памяти, воспользуетесь барьерами и отобразите IO в качестве не кэшируемого адресного пространства. – marko

1

Доступ к переменной из нескольких потоков должен выполняться с помощью специального типа variabe, называемого «атомарным». В этом случае, поскольку это int, он должен быть записан как std::atomic<int> test;.

Подробнее о технических деталях атомистики и модели памяти C++ here.

Смежные вопросы