The Concurrency Runtime provides several data structures that let you synchronize access to shared data from multiple threads. These data structures are useful when you have shared data that you modify infrequently. A synchronization object, for example, a critical section, causes other threads to wait until the shared resource is available. Therefore, if you use such an object to synchronize access to data that is used frequently, you can lose scalability in your application. The Parallel Patterns Library (PPL) provides the concurrency::combinable class, which enables you to share a resource among several threads or tasks without the need for synchronization. For more information about the combinable class, see Parallel Containers and Objects.
Sections
This topic describes the following asynchronous message block types in detail:
The concurrency::critical_section class represents a cooperative mutual exclusion object that yields to other tasks instead of preempting them. Critical sections are useful when multiple threads require exclusive read and write access to shared data.
The concurrency::reader_writer_lock class provides thread-safe read/write operations to shared data. Use reader/writer locks when multiple threads require concurrent read access to a shared resource but rarely write to that shared resource. This class gives only one thread write access to an object at any time.
The reader_writer_lock class can perform better than the critical_section class because a critical_section object acquires exclusive access to a shared resource, which prevents concurrent read access.
Like the critical_section class, the reader_writer_lock class represents a cooperative mutual exclusion object that yields to other tasks instead of preempting them.
When a thread that must write to a shared resource acquires a reader/writer lock, other threads that also must access the resource are blocked until the writer releases the lock. The reader_writer_lock class is an example of a write-preference lock, which is a lock that unblocks waiting writers before it unblocks waiting readers.
Because the reader_writer_lock class is non-reentrant, you cannot upgrade a read-only lock to a reader/writer lock or downgrade a reader/writer lock to a read-only lock. Performing either of these operations produces unspecified behavior.
Methods and Features
The following table shows the important methods that are defined by the reader_writer_lock class.
The critical_section and reader_writer_lock classes provide nested helper classes that simplify the way you work with mutual exclusion objects. These helper classes are known as scoped locks.
The critical_section class contains the concurrency::critical_section::scoped_lock class. The constructor acquires access to the provided critical_section object; the destructor releases access to that object. The reader_writer_lock class contains the concurrency::reader_writer_lock::scoped_lock class, which resembles critical_section::scoped_lock, except that it manages write access to the provided reader_writer_lock object. The reader_writer_lock class also contains the concurrency::reader_writer_lock::scoped_lock_read class. This class manages read access to the provided reader_writer_lock object.
Scoped locks provide several benefits when you are working with critical_section and reader_writer_lock objects manually. Typically, you allocate a scoped lock on the stack. A scoped lock releases access to its mutual exclusion object automatically when it is destroyed; therefore, you do not manually unlock the underlying object. This is useful when a function contains multiple return statements. Scoped locks can also help you write exception-safe code. When a throw statement causes the stack to unwind, the destructor for any active scoped lock is called, and therefore the mutual exclusion object is always correctly released.
Note
When you use the critical_section::scoped_lock, reader_writer_lock::scoped_lock, and reader_writer_lock::scoped_lock_read classes, do not manually release access to the underlying mutual exclusion object. This can put the runtime in an invalid state.
event
The concurrency::event class represents a synchronization object whose state can be signaled or non-signaled. Unlike synchronization objects, such as critical sections, whose purpose is to protect access to shared data, events synchronize flow of execution.
The event class is useful when one task has completed work for another task. For example, one task might signal another task that it has read data from a network connection or from a file.
Methods and Features
The following table shows several of the important methods that are defined by the event class.
Azure Database for PostgreSQL is a multi-user relational database solution. The ability to support many concurrent users enables PostgreSQL databases to scale out and enable applications that support many users and locations at the same time. The increase in users brings a risk of conflicts. For this reason, it's important to understand the concurrency systems that are in place in Azure Database for PostgreSQL to manage concurrency and conflicts. In this module, we look at both isolation levels and locking