One, the problem of shared memory
There is no problem when reading, there will be competition problem when writing.
Second, the solution
1, the simplest way is to adopt some kind of protection mechanism to the data structure, ensure that only the thread that modifies it can see the middle state when the invariant is destroyed. From the point of view of other access threads, the modification is either complete or not yet started.
2. Another option is to modify the design of the data structure and invariants, the modified structure must be able to complete a series of non-divided
The change of the cut, that is to ensure that each invariant remains stable state, this is called the lock-free programming. Another way to deal with conditional competition is to use transactions to handle updates to data structures. (STM)
The second is more advanced content, not within the scope of the discussion. The first is to use mutex to protect data .
Third, Std::mutex create mutual exclusion amount
1, by calling the member function lock () to lock, unlock () to unlock. It is not recommended to call member functions directly in practice, because calling member functions means that you must remember to call unlock at each function exit. The C + + standard library provides a RAII syntax template class Std::lock_guard , which provides a locked mutex at the time of construction and is unlocked at the time of the destructor, ensuring that a locked mutex is always properly unlocked. #include <mutex> header files
2. Issues of attention
The use of mutex to protect the data, not only in each member function to add a Std::lock_guard object that
Simple, a lost pointer or reference will make this protection a dummy. However, checking for lost pointers or references is
It's easy, as long as 1) No member function returns a pointer to the protected number in the form of a return value or an output parameter to its caller
A pointer or reference to a 2) member function does not invoke a pointer or reference to a function or variable that is not externally protected, and the data is safe.
classsome_data{intA; STD::stringb; Public:voiddo_something ();};
classdata_wrapper{Private: Some_data data; Std::mutex m; Public: Template<typename function>voidprocess_data (function func)//Incoming function func {Std::lock_guard<std::mutex>L (m); Func (data); //1 Passing "protect" data to user functions }};
Some_data*unprotected;voidMalicious_function (some_data&protected_data) {unprotected=&Protected_data; //The function is not protected at this time }
Data_wrapper x;voidfoo () {x.process_data (malicious_function);//2 Passing a malicious functionUnprotected->do_something ();//3 Access Protection data without protection, unprotected is the some_date type}///equivalent to a protection mechanism, the function accesses an external function that is not protected. And it destroys the protection .
means that Foo can bypass the protection mechanism and pass the function malicious_function into func ()!
Concurrent Programming (3) sharing data between threads