(Общий) мьютекс в C ++ - PullRequest
       60

(Общий) мьютекс в C ++

4 голосов
/ 19 января 2020

Я видел пример для общего мьютекса:

class MyData {
    std::vector<double> data_;
    mutable shared_mutex mut_;   // the mutex to protect data_;

public:
    void write() {
        unique_lock<shared_mutex> lk(mut_);
        // ... write to data_ ...
    }

    void read() const {
        shared_lock<shared_mutex> lk(mut_);
        // ... read the data ...
    }
};

Естественно, я бы написал вместо этого:

public:
    void write() {
        mut_.lock();
        // ... write to data_ ...
        mut_.unlock();
    }

    void read() const {
        mut_.lock_shared();
        // ... read the data ...
        mut_.unlock_shared();
    }
};

Верен ли мой путь? И есть ли разница между тем, что я использовал, и тем, что использовалось в примере? Кроме того, есть ли преимущества одного над другим? Спасибо!

Ответы [ 2 ]

11 голосов
/ 19 января 2020

Верен ли мой путь?

Подумайте, что произойдет, если код между блокировкой мьютекса и разблокировкой вызовет исключение:

void write() {
    mut_.lock();
    // <-- exception is thrown here
    mut_.unlock();
}

Тогда мьютекс остается заблокированным.

Есть ли преимущества одного над другим?

Да, unique_lock<> следует за идиомой RAII , и поэтому разблокировка мьютекса обрабатывается автоматически (т. е. его деструктором) в случае исключения:

void write() {
    unique_lock<shared_mutex> lk(mut_);
    // <-- exception is thrown
}

В случае исключения после создания объекта unique_lock<shared_mutex> - lk - его вызывается деструктор, и затем он разблокирует связанный мьютекс, если он был заблокирован (помните, что std::unique_lock, в отличие от std::lock_guard, не всегда владеет блокировкой на связанном мьютексе - см. std::defer_lock и std::unique_lock::unlock()).

Подводя итог, с помощью lock_guard / unique_lock / shared_lock не требуется никакой специальной обработки с вашей стороны в случае исключений или при выходе из функции-члена из разных путей выполнения.

4 голосов
/ 19 января 2020

Не используется необработанный мьютекс в пользу RAII-версии unique_lock (), которая безопаснее в двух ситуациях:

  • исключение
  • преждевременный возврат

Подобно необработанному указателю, как правило, избегают использования интеллектуальных указателей версии RAII: unique_ptr или shared_ptr.

В любом случае версия RAII гарантирует, что мьютекс (или указатель) всегда освобождается, когда он выходит из области видимости. .

...