2017-09-05 81 views
0

没有得到一个在线示例来生动地演示这一点。在http://en.cppreference.com/w/cpp/header/shared_mutex上看到一个例子说明了一个例子,但是 仍然不清楚。有人可以帮忙吗?共享互斥和互斥之间的区别(为什么都存在于C++ 11并发中)?

+4

您应该查看[documentation](http://en.cppreference.com/w/cpp/thread/shared_mutex)而不是标题摘要(如链接所示)。顺便说一句,这是C++ 17而不是C++ 11。最接近的是C++ 14,它是'std :: shared_timed_mutex'。尽管如此,你有没有听说过[读者 - 作家锁定](https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock)? – WhiZTiM

回答

2

“共享互斥锁通常用于多个读者可以同时访问同一资源而不引起数据竞争的情况,但只有一个作者可以这样做。”

cppreference.com

当你需要读取/写入器锁这是有用的:https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock

+0

是的,我只有线程可以同时读取数据吗?为什么读者需要锁?只有修改需要锁定才能使底层的数据结构不被破坏? –

+0

@AnandKulkarni读者需要锁定,否则他们可能会读取数据,而另一个线程正在写入相同的数据。这是为了防止数据竞争。通过读取/写入器锁定,多个读取器可以同时访问数据。 – 0xBADF00

0

通过使用正常互斥的,你能保证某种关键资源的独占访问 - 而不是其他。共享互斥通过允许访问的两级延伸此功能:共享和独占如下:

  • 独占访问防止任何其它线程获取该互斥,正如与正常的互斥。其他线程是否尝试获取共享或独占访问权限并不重要。
  • 共享访问允许多个线程获取互斥量,但是所有的只能在共享模式下使用。直到所有先前的共享持有者已经返回互斥量为止,才会授予独占访问权限(通常,只要独占请求正在等待,新共享对象在之后排队等待授予)。

一个典型的场景是数据库:多个线程同时读取一个数据和同一个数据并不重要。但修改数据库至关重要 - 如果某个线程正在读取数据,而另一个线程正在写入数据,则可能会收到不一致的数据。所以所有的阅读必须完成才能书写,新的阅读必须等到写作完成。写入后,可能会再次同时发生进一步的读取。

编辑:旁注:

为什么读者需要的锁?

这是为了防止作者在读取过程中获取锁而发生。此外,它还可以防止新读者在专门持有锁的情况下获得锁。

+0

非常清楚的理解,我们不希望读者在修改正在发生时读取陈旧的数据,反之亦然,因为目前正在进行读取,所以我们不希望作者开始进行更改以保持数据一致 –

0

共享互斥锁有两个访问级别'shared'和'exclusive'。 多个线程可以获得共享访问权限,但只有一个可以拥有“独占”访问权限(包括没有共享访问权限)。

常见的情况是读/写锁。回想一下Data Race只能在两个线程访问相同的数据时发生其中至少有一个是写

利用这些数据可能会被许多读者读取,但是当作者需要访问时,他们必须获得数据的独占访问权。

下面是一个示例(稍后从示例http://en.cppreference.com/w/cpp/thread/shared_mutex稍微改编)。

#include <iostream> 
#include <mutex> // For std::unique_lock 
#include <shared_mutex> 
#include <thread> 


std::mutex cout_mutex; 
void log(const std::string& msg){ 
    std::lock_guard guard(cout_mutex); 
    std::cout << msg << std::endl; 
} 

class ThreadSafeCounter { 
public: 
    ThreadSafeCounter() = default; 

    // Multiple threads/readers can read the counter's value at the same time. 
    unsigned int get() const { 
    std::shared_lock lock(mutex_);//NB: std::shared_lock will shared_lock() the mutex. 
    log("get()-begin"); 
    std::this_thread::sleep_for(std::chrono::milliseconds(500)); 
    auto result=value_; 
    log("get()-end"); 
    return result; 
    } 

    // Only one thread/writer can increment/write the counter's value. 
    void increment() { 
    std::unique_lock lock(mutex_); 
    value_++; 
    } 

    // Only one thread/writer can reset/write the counter's value. 
    void reset() { 
    std::unique_lock lock(mutex_); 
    value_ = 0; 
    } 

private: 
    mutable std::shared_mutex mutex_; 
    unsigned int value_ = 0; 
}; 

int main() { 
    ThreadSafeCounter counter; 

    auto increment_and_print = [&counter]() { 
    for (int i = 0; i < 3; i++) { 
     counter.increment(); 
     auto ctr=counter.get(); 
     { 
      std::lock_guard guard(cout_mutex); 
      std::cout << std::this_thread::get_id() << ' ' << ctr << '\n'; 
     } 
    } 
    }; 

    std::thread thread1(increment_and_print); 
    std::thread thread2(increment_and_print); 
    std::thread thread3(increment_and_print); 

    thread1.join(); 
    thread2.join(); 
    thread3.join(); 
} 

可能的部分输出:

get()-begin 
get()-begin 
get()-end 
140361363867392 2 
get()-end 
140361372260096 2 
get()-begin 
get()-end 
140361355474688 3 
//Etc... 

通知如何两个get()-begin()返回显示,两个线程的读取期间保持共享锁。