нужна ли функции-получателю мьютекс? - PullRequest
9 голосов
/ 12 февраля 2010

У меня есть класс, доступ к которому осуществляется из нескольких потоков. Функции как getter, так и setter защищены замками. Надежно ли нужны блокировки для функций получения? Почему?

class foo {
public:
    void setCount (int count) {
        boost::lock_guard<boost::mutex> lg(mutex_);
        count_ = count;
    }

    int count () {
        boost::lock_guard<boost::mutex> lg(mutex_); // mutex needed?
        return count_;
    }

private:
    boost::mutex mutex_;
    int count_;
};

Ответы [ 6 ]

14 голосов
/ 12 февраля 2010

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

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

5 голосов
/ 12 февраля 2010

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

Но если это просто int, и вы уверены, что int является атомарным типом (т. Е. Процессору не нужно будет делать два отдельных чтения из памяти, чтобы загрузить int в регистр), и вы Если вы оценили производительность и определили, что вам нужна более высокая производительность, то вы можете снять блокировку как с геттера, так и с сеттера. Если вы это сделаете, убедитесь, что квалифицировали int как volatile. И напишите комментарий, объясняющий, почему у вас нет мьютекс-защиты, и при каких условиях она вам понадобится, если класс изменится.

Кроме того, помните, что у вас нет такого кода:

void func(foo &f) {
  int temp = f.count();
  ++temp;
  f.setCount(temp);
}

Это не потокобезопасно, независимо от того, используете ли вы мьютекс или нет. Если вам нужно сделать что-то подобное, защита мьютекса должна быть вне функций сеттера / геттера.

4 голосов
/ 12 февраля 2010

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

2 голосов
/ 12 февраля 2010

в вашем случае, вероятно, нет, если ваш 32-битный процессор, однако, если count является сложным объектом или процессору требуется более одной инструкции для обновления его значения, тогда да

1 голос
/ 12 февраля 2010

Это зависит от точной реализации блокируемого объекта. Однако, как правило, вы не хотите, чтобы кто-то изменял (устанавливал?) Объект, пока кто-то еще находился в процессе его чтения (получения?). Самый простой способ предотвратить это - заблокировать его.

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

1 голос
/ 12 февраля 2010

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

...