Многопоточность: нужно ли защищать мою переменную только для чтения? - PullRequest
5 голосов
/ 23 марта 2012

У меня есть несколько вопросов об использовании блокировки для защиты моей общей структуры данных.Я использую C / C ++ / ObjC / Objc ++

Например, у меня есть класс счетчика, который используется в многопоточной среде

class MyCounter {
private:
    int counter;
    std::mutex m;

public:
    int getCount() const {
        return counter;
    }
    void increase() {
        std::lock_guard<std::mutex> lk(m);
        counter++;
    }
};
  1. Нужно ли использоватьstd::lock_guard<std::mutex> lk(m); в getCount() метод, чтобы сделать его потокобезопасным?

  2. Что произойдет, если есть только два потока: поток чтения и поток записи, тогда я должен защищать егосовсем?Поскольку существует только один поток, модифицирующий переменную, поэтому я думаю, что потерянное обновление не произойдет.

  3. Если для переменной общего типа примитива имеется несколько устройств записи / чтения (например, int)какая катастрофа может произойти, если я заблокирую только метод записи, но не метод чтения?Будет ли 8-битный тип иметь какую-либо разницу по сравнению с 64-битным типом?

  4. Является ли какой-нибудь примитивный тип атомарным по умолчанию?Например, запись в char всегда атомарна?(Я знаю, что это верно в Java, но не знаю о c ++, и я использую компилятор llvm на Mac, если платформа имеет значение)

Ответы [ 4 ]

7 голосов
/ 23 марта 2012

Да, если вы не можете гарантировать, что изменения базовой переменной counter являются атомарными, вам нужен мьютекс.

Классический пример, скажем, counter - это двухбайтовое значение, которое увеличивается на (не-атомные) этапы:

add 1 to lower byte
if lower byte is 0:
    add 1 to upper byte

и начальное значение 255.

Если между каким-либо изменением нижнего байта и изменением верхнего байта появится другой поток, он будет читать 0 вместоправильные 255 (перед приращением) или 256 (после приращения).

С точки зрения того, какие типы данных являются атомарными, последний стандарт C ++ определяет их в заголовке <atomic>.

Если у вас нет возможностей C ++ 11, то все зависит от реализации, какие типы являются атомарными.

3 голосов
/ 23 марта 2012

Да, в этом случае вам также необходимо заблокировать чтение.

Есть несколько альтернатив - замок довольно тяжелый. Атомарные операции являются наиболее очевидными (без блокировки). Есть и другие подходы к блокировке в этом проекте - блокировка чтения и записи является одним из примеров.

1 голос
/ 23 марта 2012

Да, я считаю, что вам также необходимо заблокировать чтение. Но поскольку вы используете функции C ++ 11, почему бы вам не использовать std::atomic<int> counter; вместо этого?

0 голосов
/ 23 марта 2012

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

Вы можете использовать доступные технические приемы синхронизации, такие как: Mutex, Lock, Атрибут синхронизации (доступно для MS c ++)

...