shared_lock

shared_lock is to ::std::shared_mutex what unique_lock is to ::std::mutex. shared_lock locks a shared_mutex, but allows concurrent use of the mutex by other shared_lock objects. Once locked using lock_guard, all shared_locks are excluded. This allows multiple-reader single-writer behaviour: multiple shared_locks can lock a shared_mutex simultaneously, but only one lock_guard can lock it at a time.

#include <syncstream>
#include <iostream>

#include <thread>
#include <shared_mutex>
#include <memory>
#include <vector>

::std::shared_mutex
   mutex;

::std::string
   content = "Initial Content";

//
// Read the content:
//

void read_action(unsigned reader_index)
{
   ::std::shared_lock
      <
      ::std::shared_mutex
      >
      lock
         (
         mutex
         )
         ;
   
   ::std::osyncstream(::std::cout) << "Reader "
                                   << reader_index
                                   << " reads: \""
                                   << content
                                   << "\""
                                   << ::std::endl
                                      ;
}

//
// Modify (write to) the content:
//

void write_action(void)
{
   ::std::lock_guard
      <
      ::std::shared_mutex
      >
      lock
         (
         mutex
         )
         ;
   
   content = "Modified Content";
   
   ::std::osyncstream(::std::cout) << "Writer wrote: \""
                                   << content
                                   << "\""
                                   << ::std::endl
                                      ;
}

int main(int argc, char ** argv)
{
   //
   // Create multiple content readers and only 1 writer:
   //
   
   ::std::vector
      <
      ::std::thread
      >
      reader_threads;
   
   ::std::unique_ptr
      <
      ::std::thread
      >
      writer_thread;
   
   ::std::size_t
      number_of_threads(10u);
   
   reader_threads.reserve( number_of_threads );
   
   for(unsigned i(0u); i< number_of_threads; ++i)
   {
      reader_threads.push_back
         (
         ::std::thread(read_action, i)
         )
         ;
   }
   
   writer_thread =
      ::std::make_unique
         <
         ::std::thread
         >
         (
         write_action
         )
         ;
   
   for(auto & thread : reader_threads)
   {
      thread.join();
   }
   
   writer_thread->join();
   
   return 0;
}
Possible output:
Reader 1 reads: "Initial Content" Reader 0 reads: "Initial Content" Reader 2 reads: "Initial Content" Reader 4 reads: "Initial Content" Reader 5 reads: "Initial Content" Reader 3 reads: "Initial Content" Reader 6 reads: "Initial Content" Reader 7 reads: "Initial Content" Reader 8 reads: "Initial Content" Writer wrote: "Modified Content" Reader 9 reads: "Modified Content"