C ++ concurrency in action Reading Notes -- Part 4 Chapter 5 multi-thread Memory Model of C ++ (1)

Source: Internet
Author: User

C ++ concurreny in Action Chapter 5 Memory Model and atomic operation of C ++

5.1 Memory Model BASICS (Internal Model basics)

Memory Model involves two aspects: structural and concurrency

Structural is the foundation, mainly the object layout.

5.1.1 objects and memory location

The C ++ standard defines an object as "a region of storage ,"

Note:

  • All variables have objects, including member variables.
  • All objects have their own memory locations.
  • Basic Types (such as INT) all have their own separate memory areas
  • Bit Field shares the same memory Zone

5.1.2 objects, memory locations, and concurrency

The condition that a race condition is generated is that multiple threads access the same memory location, and at least one value is modifying this memory location.

You must control the access order to avoid race condition. Two methods: 1. Lock (mutex) 2. atomic operation (atomic operation)

5.1.3 modification orders

The order of data modification must be limited. Otherwise, data race is generated.

5.2 atomic operations and types in C ++ (atomic operations and types in C ++)

An atomic operationis an indivisible operation.

Atomic operations are inseparable operations. Or you have not done it yet. It is impossible to see the "only half done" status

In C ++, we can perform atomic operations through the atomic type.

5.2.1 tThe standard atomic types

The standard atomic types are all in the header file <atomic>. Here, all operations of the header type are atomic operations.

Most of them have the is_lock_free () member function. If true is returned, this is a "real atomic operation (using real atomic operation commands)" and false is returned, the lock is used for simulation.

Only STD: atomic_flag does not have the is_lock_free function. This type must be a real atomic operation.

Other atomic types are implemented using STD: Atomic <>.

The atomic types in the standard library are not copyable or assignable)

Each atomic operation function has a memory-ordering parameter option, which can precisely control the memory-ordering semantics. However, this is detailed in section 5.3.

There are three types of atomic operations:

  • (Storage operation) store operations, which has the following functions: memory_order_relaxed, memory_order_release, or memory_order_seq_cstordering
  • (Load operation ?) Load operations: memory_order_relaxed, memory_order_consume, memory_order_acquire, or memory_order_seq_cstordering
  • (Modify operation) read-Modify-write operations, which have the following functions: memory_order_relaxed, memory _

Order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, or memory_order_seq_cstordering

5.2.2 operations on STD: atomic_flag

STD: atomic_flag is the simplest atomic type in the standard library and represents a bool flag. This type of object has two states: set or clear. This type is designed to build other atomic types, so it is rarely used by common programs. However, this book starts from this type because it is representative.

STD: The atomic_flag object must be initialized with atomic_flag_init. After initialization, the object will be in the clear state. (It is the only atomic type with special requirements for initialization, but it is also the only atomic type that will be guaranteed to be implemented by lock_free ). Static STD: atomic_flag will also be initialized by the compiler.

STD: atomic_flag F = atomic_flag_init;

Three operations can be performed on an initialized STD: atomic_flag object:

  • Destroy (through destructor)
  • The clear (through the clear () function) store operation parameter can specify memory-ordering tags, but the memory_order_acquire or memory_order_acq_rel semantics cannot be used.
  • Set and read the status (through the test_and_set () function) read_modify_write operation, you can use any memory-ordering tags.
f.clear(std::memory_order_release); bool x=f.test_and_set();

The atomic operations of the standard library are atomic operations. The Atomic types of the standard library do not contain copies and assignments, because the copy and assignment cannot be "Atomic operations" (involving two objects ).

Since there are only a few key operations, STD: atomic_flag is suitable for implementation of spin locks.

class spinlock_mutex{    std::atomic_flag flag;public:    spinlock_mutex():flag(ATOMIC_FLAG_INIT)    { }    void lock()    {        while(flag.test_and_set(std::memory_order_acquire));    }    void unlock()    {        flag.clear(std::memory_order_release);    }};

This implementation is very simple, but it can be used as a mutex lock on STD: lock_guard <>.

STD: atomic_flag operations are too limited, so they cannot be used as a common bool sign (because there is no simple value read operation ). If a common bool flag is required, STD: Atomic <bool> should be used.

5.2.3 operations on STD: Atomic <bool>

STD: Atomic <boo> can be built using a bool value.

std::atomic<bool> b(true);b=false;

STD: assign values of the atomic type to return values rather than references. For example, the value assignment operation (STD: Atomic <int> Returns int instead of Int &) to avoid obtaining the reference from other threads and modifying it through non-atomic operations.

Unlike STD: atomic_flag, STD: Atomic <boo> uses the following methods:

  • Store () => value assignment, you can specify memory_older
  • Load () => get the value of an atomic object
  • Exchange () => read_modify_write operation.

The following is an example:

std::atomic<bool> b;bool x=b.load(std::memory_order_acquire);b.store(true);x=b.exchange(false,std::memory_order_acq_rel);

STD: Atomic <boo> there are some other read_modify_write operations:

Compare_exchange_weak (T & expected, t desired ,......) And compare_exchange_strong (T & expected, t desired ,......)

These two functions only focus on the first two parameters (so the ellipsis is entered later. Note that these two functions are not "variable parameter functions ~"), The function is as follows: if the object value is the same as expected, it is assigned as desired. If the object value is different from expected, the expected value is assigned to the current object value.

(I: Actually, Using STD: Atomic <bool> as an example, the two parameters are a little obscure. I can understand them much better if I use Int)

The return values of these two functions are of the bool type. True indicates that the store operation is performed, and false indicates that the operation is not performed. The difference is that: compare_exchange_weak may have the same object value as expected, and the function may return false, because assigning desired to the object will fail (especially for CPUs without compare/exchange instructions ), the value of the STD: Atomic object will not be updated in case of failure. If compare_exchange_strong returns false, the object value is different from expected.

(You can also specify memory_older for these two parameters. To be honest, I basically didn't understand it now. I should try again after reading 5.3 .)

5.2.4 operations on STD: Atomic <t *>: pointer Arithmetic

The atomic type of the pointer to a T object. Basically, STD: Atomic <bool> has all the operations described above. But there are some "pointer operations ". Fetch_add () and fetch_sub () are the corresponding distances between "Forward" and "backward. And ++ and -- with + =,-=, and prefix and suffix --. Note that fetch_xx returns the original value instead of the calculated value ).

The semantics of + =,-=, ++, -- and so on are exactly the same as the pointers we usually use.

class Foo{};Foo some_array[5];std::atomic<Foo*> p(some_array);Foo* x=p.fetch_add(2); assert(x==some_array);assert(p.load()==&some_array[2]);x=(p-=1); assert(x==&some_array[1]);assert(p.load()==&some_array[1]);

5.2.5 operation on standard atomic integral types

The atomic operations of other integer types are basically the same. In this section, we will give an overview: (load (), store (), exchange (), compare_exchange_weak (), and compare_exchange_strong. There are also: fetch_add (), fetch_sub (), fetch_and (), fetch_or (),

Operations such as fetch_xor () represent: (+ =,-=, & =, | =, and ^ =), and --, ++ with the prefix suffix. But there is no multiplication, division, and bitwise operation. However, since the atomic type is generally used for counting, we will not feel much inconvenience. You can also use compare_exchange_weak () and loop to obtain it if necessary.

5.2.6 the STD: Atomic <> primary class template

You can use atomic <> to customize the atomic type, but there are many restrictions on the parameters in the template. we can consider this as follows: it is acceptable that the type of bitwise compare can be used as t in atomic <t>. (For details, refer to the original article)

5.2.7 free functions for atomic operations

All of the above are STD: Atomic member functions. In fact, they all have corresponding free function versions. The following table is supported:

The free function is designed more C, so the reference is replaced with a pointer.

In addition, the C ++ Standard Library provides some important auxiliary functions for STD: shared_ptr, so that these smart pointers can obtain and set values in an atomic operation mode.

std::shared_ptr<my_data> p;void process_global_data(){    std::shared_ptr<my_data> local=std::atomic_load(&p);    process_data(local);}void update_global_data(){    std::shared_ptr<my_data> local(new my_data);    std::atomic_store(&p,local);}

They all use STD: shared_ptr <> * as the first parameter, mainly including load, store, exchange and compare/exchange.

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.