Study notes "C ++ concurrent programming combat" (3) - data sharing among threads

Competitive conditions: 
    when the process each thread can share data, both advantage and a disadvantage, leading to abnormal operating data appear different threads, competitive conditions is one of them. 

Avoid race conditions: 
    1: The protection mechanism, the data structure of the package is being modified or accessed to ensure that other threads can access visible in the shared data is modified before or after the modification. 
    II: modifying the data structure design, use or invariant, such as program lock-free (no lock data structures, etc.). 
    
Mutex protection: 
    mutex as synchronization primitives to ensure that when a thread gets locked shared data resources, and post-processing to unlock resources, other threads can access the resource is visible. 
    But it needs careful handling mutex to ensure that no deadlock, protection of too much, too little data. 
    std :: mutex lock operation of the basic package, in addition to using a template class std :: lock_guard implement RAII mutex usage to avoid explicit call Lock / UNLOCK interfaces. 
    Further mutex generally shared data protected together, as a class, and needs careful design to avoid leakage of the protected data (eg: thrown or address referencing or passed 
    to other shared access to protected external functions, etc.) data. When a thread already holds std :: mutex lock, the exception if the thread acquires the lock will appear again, and you should use 
    a recursive lock std :: recursive_mutex. 

Deadlock: 
    general have each other's lock resources in two or more threads wait for a lock Shique release other resources owned by each other. And produce a deadlock. This situation often occurs in the need to lock two
    Or more the case when a mutex or other primitive to the most frequently occurring when performing operations. Other scenarios include waiting for the other thread from each other or other resources or the need to synchronize. 
    
General practice to avoid deadlock: 
    Always lock mutex or two or more other primitives use the same order. Nevertheless, this may also lead to a deadlock (e.g., the same instance of an object to perform switching operation). 
    Std :: lock case by means of a template can function simultaneously locks and lock the two or more binding template class std :: lock_guard to release the lock has been locked (by occupying std :: adopt_lock identification 
    configuration mode when a). std :: lock function template can be achieved in a manner similar matters, either simultaneously acquire the lock or have failed. 

Other ways to avoid deadlock: 
    1 . Avoid locking nested; i.e., at most a single thread holding a lock to prevent further acquire other locks, if desired in addition acquiring a plurality of locks, should be used in conjunction with a template function std :: lock acquire multiple locks.
    2 . Avoid holding the lock, and then call the user-supplied code: The code provided by the customer may introduce the operation to acquire the lock, which may lead to deadlock when acquiring multiple locks appeared.
    3 . Acquire lock in a fixed order: For a plurality of locks needs to obtain without the use of templates std :: lock function, each thread should acquire the lock in the same order.
    4 Use locks in a hierarchical manner: for each mutex or other primitive distribution layer number, and records what each thread lock mutex. When the code tries to lock a mutex, if it is in the more low-level 
       lock is held, it is not allowed to acquire the mutex (i.e., the layer number than the mutex has been locked by the layer number mutex equal or higher, or acquire the mutex lower level number is permitted). 
    5. Std :: unique_lock template lock, the lock template std :: lock_guard relatively more flexible and do not need to own the lock object and there is lock / unlock / . Recursive lock std :: recursive_mutex; can achieve multiple acquire the same lock, but to be acquired and released in pairs. Std :: unique_lock may be combined or preventing acquired std :: lock_guard tryLock like interface to operate the lock;
       But it occupies little space and some loss of efficiency, in addition to the template lock also supports the transfer of ownership that is std :: move semantics. 
    
Locking granularity: 
    respond to the protection needs of shared data be locked to avoid particle size is too large or too small. May lead to multi-threaded performance is too large. 
    Moreover lock not only need to be concerned about the time when the lock granularity also holds the lock, avoid prolonged hold the lock. 
    
Other protection mechanisms or tools to share data: 
    1 . To protect shared data at initialization: protection for the first time initialization. (Secondary inspection lock some problems, namely data races, different threads when reading or write pointer to an object or 
       not synchronized), std :: once_flag and std :: call_once solve such problems. In fact, for the return of local static objects in the early C ++ may be a problem there will be 11 before the competition, 
       but C ++ is returned after 11 local static objects are also safe and can replace std :: call_once of.
    2 . Protection rarely updated data structures, such as read-write locks, i.e., a single exclusive write lock, a plurality of shared read lock. To reduce the read operation and the data structure is frequently protected by locks.
    3
       Inconsistent with the release of the lock situation. Recursive locks are usually not recommended, and you should consider redesigning or remodeling achieve partial implementation in order to avoid recursive locks.

 

Guess you like

Origin www.cnblogs.com/haomiao/p/11647391.html