線程間共用數據的問題 多線程之間共用數據,最大的問題便是數據競爭導致的異常問題。多個線程操作同一塊資源,如果不做任何限制,那麼一定會發生錯誤。例如: 1 int g_nResource = 0; 2 void thread_entry() 3 { 4 for (int i = 0; i < 1000 ...
1 int g_nResource = 0; 2 void thread_entry() 3 { 4 for (int i = 0; i < 10000000; ++i) 5 g_nResource++; 6 } 7 8 int main() 9 { 10 thread th1(thread_entry); 11 thread th2(thread_entry); 12 th1.join(); 13 th2.join(); 14 cout << g_nResource << endl; 15 return 0; 16 }
10161838
1 int g_nResource = 0; 2 std::mutex _mutex; //使用互斥 3 void thread_entry() 4 { 5 _mutex.lock(); //加鎖 6 for (int i = 0; i < 10000000; ++i) 7 g_nResource++; 8 _mutex.unlock(); //解鎖 9 }
輸出:
20000000
1 mutex(); 2 3 //不支持拷貝構造,也不支持移動構造(有定義拷貝,則無移動) 4 mutex(const mutex&) = delete; 5 mutex& operator=(const mutex&) = delete;
1 void lock();
1 void unlock();
bool try_lock();
1 int g_nResource = 0; 2 std::mutex _mutex; 3 void thread_entry() 4 { 5 while (1) 6 { 7 if (_mutex.try_lock()) 8 { 9 cout << this_thread::get_id() << " get lock\n"; 10 for (int i = 0; i < 10000000; ++i) 11 g_nResource++; 12 _mutex.unlock(); 13 return; 14 } 15 else 16 { 17 cout << this_thread::get_id() << " no get lock\n"; 18 this_thread::sleep_for(std::chrono::milliseconds(500)); 19 } 20 } 21 } 22 23 int main() 24 { 25 thread th1(thread_entry); 26 thread th2(thread_entry); 27 th1.join(); 28 th2.join(); 29 cout << "Result = " << g_nResource << endl; 30 }
131988 get lock 136260 no get lock 136260 get lock Result = 20000000
1 template <class _Mutex> 2 class _NODISCARD lock_guard { // class with destructor that unlocks a mutex 3 public: 4 using mutex_type = _Mutex; 5 6 explicit lock_guard(_Mutex& _Mtx) : _MyMutex(_Mtx) { // construct and lock 7 _MyMutex.lock(); 8 } 9 10 lock_guard(_Mutex& _Mtx, adopt_lock_t) : _MyMutex(_Mtx) {} // construct but don't lock 11 12 ~lock_guard() noexcept { 13 _MyMutex.unlock(); 14 } 15 16 lock_guard(const lock_guard&) = delete; 17 lock_guard& operator=(const lock_guard&) = delete; 18 19 private: 20 _Mutex& _MyMutex; 21 };
1 int g_nResource = 0; 2 std::mutex _mutex; 3 void thread_entry() 4 { 5 lock_guard<mutex> lock(_mutex); 6 for (int i = 0; i < 10000000; ++i) 7 g_nResource++; 8 }
1 std::lock(lhs._mutex, rhs._mutex); //對lhs、rhs上鎖 2 std::lock_guard<mutex> lock_a(lhs._mutex, std::adopt_lock); //不在上鎖 3 std::lock_guard<mutex> lock_b(rhs._mutex, std::adopt_lock); //不在上鎖
1 class SomeData 2 { 3 public: 4 void DoSomething() { cout << "do something\n"; } 5 }; 6 7 class Operator 8 { 9 public: 10 void process(std::function<void(SomeData&)> func) 11 { 12 std::lock_guard<mutex> lock(_mutex); 13 func(data); //數據外溢 14 } 15 16 private: 17 SomeData data; 18 mutex _mutex; 19 }; 20 21 void GetDataPtr(SomeData** pPtr, SomeData& data) 22 { 23 *pPtr = &data; 24 } 25 26 int main() 27 { 28 Operator opt; 29 SomeData* pUnprotected = nullptr; 30 auto abk = [pUnprotected](SomeData& data) mutable 31 { 32 pUnprotected = &data; 33 }; 34 opt.process(abk); 35 pUnprotected->DoSomething(); //以無鎖形式訪問本應該受到保護的數據 36 }
1 void func() 2 { 3 stack<int> s; 4 if (!s.empty()) 5 { 6 int nValue = s.top(); 7 s.pop(); 8 do_something(nValue); 9 } 10 }
template<typename T> class myStack { public: myStack(); ~myStack(); void pop(T& data); //傳入引用接收數據 }; int main() { myStack<DataRes> s; DataRes result; s.pop(result); }
1 class A 2 { 3 public: 4 A(int nValue) : m_nValue(nValue) {} 5 friend void Swap(A& lhs, A& rhs) 6 { 7 if (&lhs == &rhs) return; 8 lock_guard<mutex> lock_a(lhs._mutex); 9 lock_guard<mutex> lock_b(rhs._mutex); 10 std::swap(lhs.m_nValue, rhs.m_nValue); 11 } 12 private: 13 int m_nValue; 14 mutex _mutex; 15 }; 16 17 void func(A& lhs, A& rhs) 18 { 19 Swap(lhs, rhs); 20 } 21 22 int main() 23 { 24 A a1(10); 25 A a2(20); 26 thread th1(func, std::ref(a1), std::ref(a2)); //傳入參數順序不同 27 thread th2(func, std::ref(a2), std::ref(a1)); //傳入參數順序不同 28 th1.join(); 29 th2.join(); 30 }
1 class A 2 { 3 public: 4 A(int nValue) : m_nValue(nValue) {} 5 6 friend void Swap(A& lhs, A& rhs) 7 { 8 if (&lhs == &rhs) return; 9 std::lock(lhs._mutex, rhs._mutex); 10 std::lock_guard<mutex> lock_a(lhs._mutex, std::adopt_lock); //已經上鎖,不再加鎖 11 std::lock_guard<mutex> lock_b(rhs._mutex, std::adopt_lock); //已經上鎖,不再加鎖 12 std::swap(lhs.m_nValue, rhs.m_nValue); 13 } 14 15 private: 16 int m_nValue; 17 mutex _mutex; 18 };
1 scoped_lock<mutex, mutex> lock(lhs._mutex, rhs._mutex);
1 scoped_lock lock(lhs._mutex, rhs._mutex);
unique_lock(); unique_lock(_Mutex&); //構造並調用lock上鎖 ~unique_lock(); //析構並調用unlock解鎖 //構造,_Mtx已經被鎖,構造函數不在調用lock unique_lock(_Mutex&, adopt_lock_t); //構造,但不對_Mtx上鎖,需後續手動調用 unique_lock(_Mutex&, defer_lock_t) //構造,嘗試獲取鎖,不會造成阻塞 unique_lock(_Mutex&, try_to_lock_t) //構造 + try_lock_shared_for unique_lock(_Mutex&, const chrono::duration<_Rep, _Period>&); //構造 + try_lock_shared_until unique_lock(_Mutex&, const chrono::time_point<_Clock, _Duration>&); unique_lock(unique_lock&& _Other); //移動構造 //若占有則解鎖互斥,並取得另一者的所有權 unique_lock& operator=(unique_lock&& _Other); //無拷貝構造 unique_lock(const unique_lock&) = delete; unique_lock& operator=(const unique_lock&) = delete;
//鎖定關聯互斥 void lock(); //解鎖關聯互斥 void unlock(); //嘗試鎖定關聯互斥,若互斥不可用則返回 bool try_lock(); //試圖鎖定關聯的可定時鎖定 (TimedLockable) 互斥,若互斥在給定時長中不可用則返回 bool try_lock_for(const chrono::duration<_Rep, _Period>&); //嘗試鎖定關聯可定時鎖定 (TimedLockable) 互斥,若抵達指定時間點互斥仍不可用則返回 bool try_lock_until(const chrono::time_point<_Clock, _Duration>&); //與另一 std::unique_lock 交換狀態 void swap(unique_lock& _Other); //將關聯互斥解關聯而不解鎖它 _Mutex* release(); //測試是否占有其關聯互斥 bool owns_lock(); //同owns_lock operator bool(); //返回指向關聯互斥的指針 _Mutex* mutex();
1 std::mutex _Mtx; 2 3 void PrepareData() {} 4 5 void DoSomething() {} 6 7 std::unique_lock<std::mutex> get_lock() 8 { 9 std::unique_lock<std::mutex> lock(_Mtx); 10 PrepareData(); 11 return lock; 12 } 13 14 void ProcessData() 15 { 16 std::unique_lock<std::mutex> lock(get_lock()); 17 DoSomething(); 18 }
1 std::mutex _Mtx; 2 bool GetAndProcessData() 3 { 4 std::unique_lock<std::mutex> lock(_Mtx); 5 DataResource data = GetData(); 6 lock.unlock(); 7 bool bResult = WirteToFile(data); //非常耗時 8 lock.lock(); 9 SaveResult(bResult); 10 return bResult; 11 }
1 class Y 2 { 3 private: 4 int some_detail; 5 mutable std::mutex m; 6 int get_detail() const 7 { 8 std::lock_guard<std::mutex> lock_a(m); 9 return some_detail; 10 } 11 public: 12 Y(int sd):some_detail(sd){} 13 friend bool operator==(Y const& lhs, Y const& rhs) 14 { 15 if(&lhs==&rhs) 16 return true; 17 int const lhs_value=lhs.get_detail(); 18 int const rhs_value=rhs.get_detail(); 19 return lhs_value==rhs_value; ⇽--- ④ 20 } 21 };