вопрос о std :: shared_mutex: потоки / читатель не могут читать переменные одновременно - PullRequest
0 голосов
/ 29 апреля 2020

вот мой код

#include <iostream>
#include <mutex>
#include <shared_mutex>
#include <thread>
#include <windows.h>

using namespace std;
class Counter {
public:
    Counter() : value_(0) {
    }

    // Multiple threads/readers can read the counter's value at the same time.
    std::size_t Get() const {
        std::shared_lock<std::shared_mutex> lock(mutex_);
        std::cout << std::this_thread::get_id() << ' ' << value_ << std::endl;
        Sleep(1000);
        return value_;
    }

    // Only one thread/writer can increment/write the counter's value.
    void Increase() {
        // You can also use lock_guard here.
        std::unique_lock<std::shared_mutex> lock(mutex_);
        value_++;
        lock.unlock();
    }

private:
    mutable std::shared_mutex mutex_;
    std::size_t value_;
};



void Worker(Counter& counter) {
    counter.Get();
    counter.Increase();
    counter.Get();
}

#include <vector>
int main() {
    Counter counter;
    std::vector<std::thread> v;
    for(int i(0);i<10;i++){v.emplace_back(&Worker, std::ref(counter));}
    for (std::thread& t : v) t.join();
    return 0;
}

И результат примерно такой:

12188457610048 10196 06744
3692  0011812 8392 6912  00
10392 00
0

0
0



6744 1
3692 2
11812 3
10048 4
4576 5
10392 6
8392 7
10196 8
12188 9
6912 10

Это довольно странно: в первый раз я запускаю "counter.Get ()" , все потоки читателей читают одновременно. Но во второй раз снова запустите counter.Get () после использования counter.Increase (), все потоки читателей просто должны ждать 1 se c, чтобы получить ответ. Почему это? Есть ли что-нибудь, что я могу сделать, чтобы исправить это?

Ответы [ 2 ]

2 голосов
/ 29 апреля 2020

Поскольку ссылка

Если один поток получил общую блокировку (через lock_shared, try_lock_shared), никакой другой поток не может получить эксклюзивную блокировку, но может получить общую блокировку .

Первый Get выполняется одновременно для всех работников, поскольку получен только shared_lock. Однако операция Increase требует монопольной блокировки. Теперь, после освобождения исключительной блокировки из операции Increase, вы сразу же получаете общую блокировку во второй операции Get, в результате чего все потоки, которые еще не вызвали Increase, ожидают 1se c, пока Get не снимет блокировку.

1 голос
/ 29 апреля 2020

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

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

C ++ Standard не определяет, являются ли мьютексы C ++ честными или нечестными.

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

...