C++11:多線程(1)

前言

之前的工作項目基本不使用多線程,一直對多線程的理解比較淺顯,一般應用也是主從兩個線程,也不涉及資源鎖,以及其他的各種鎖,信號量之類的,更別提線程池之類的,這次也特意學習記錄一下多線程。

庫知識

C++11現在也有了自己的多線程庫,從C++11的線程庫開始學習瞭解。
庫主要分爲:

#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <future>

std::thread

std::thread類,主要用來創建創建線程,對線程對象進行相關操作,控制線程的生命週期。
std::thread 類成員函數主要如下:

//構造函數
thread() noexcept = default;
thread(thread&) = delete;
thread(const thread&) = delete;
thread(const thread&&) = delete;
thread(thread&& __t) noexcept     { swap(__t); }
//析構函數
  ~thread()
   {
     if (joinable())
std::terminate();
   }
//交換函數,用來交換底層句柄
void    swap(thread& __t) noexcept    { std::swap(_M_id, __t._M_id); }
//join狀態函數,判斷線程是否能被線程控制
bool  joinable() const noexcept   { return !(_M_id == id()); }//join 等待線程執行結束
void join();
//線程分離函數
void detach();
//得到線程ID
thread::id get_id() const noexcept { return _M_id; }
//native_handle_type 得到與操作系統相關的原生線程句柄
 typedef __gthread_t			native_handle_type;
 native_handle_type native_handle() { return _M_id.M_thread; }
 //hardware_concurrency 獲得當前程序最大支持的線程數,多線程一般代表系統核數
 static unsigned int hardware_concurrency() noexcept;

std::mutex

互斥鎖,主要用來線程同步,保證在同一時間內只有一個線程對某一資源進行讀寫操作。
std::mutex 類主要有以下幾種類,mutex,recursive_mutex,timed_mutex,recursive_timed_mutex幾種類。

mutex

基礎類:

//加鎖
void lock();
//解鎖
void unlock();
//嘗試鎖
bool try_lock();

recursive_mutex

遞歸鎖:允許在同一個線程內,多一個互斥量進行多次請求。即在同一個線程內,多次獲取鎖定同一個遞歸鎖,且不會產生死鎖。

//構造函數
recursive_mutex() = default;
recursive_mutex(const recursive_mutex&) = delete;
//析構函數
~recursive_mutex() = default;
//加鎖
void lock();
//解鎖
void unlock();
//嘗試鎖
bool try_lock();

timed_mutex

定時鎖:

//構造函數
timed_mutex() = default;
timed_mutex(const timed_mutex&) = delete;
//析構函數
~timed_mutex() = default;
//加鎖
void lock();
//解鎖
void unlock();
//嘗試鎖
bool try_lock();
//等待鎖,在調用時,在一個時間段內,如果鎖被釋放,加鎖,否則,返回false。
template <class _Rep, class _Period>
bool try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) { return _M_try_lock_for(__rtime); }
//等待鎖,在某個時刻到達之前,如果鎖被釋放,加鎖,否則,返回false
template <class _Clock, class _Duration>
bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) { return _M_try_lock_until(__atime); }

recursive_timed_mutex

遞歸定時鎖:具備遞歸鎖和定時鎖的所有特性。

//構造函數
recursive_timed_mutex() = default;
recursive_timed_mutex(const recursive_timed_mutex&) = delete;
//析構函數
~recursive_timed_mutex() = default;
//加鎖
void lock();
//解鎖
void unlock();
//嘗試鎖
bool try_lock();
//等待鎖,在調用時,在一個時間段內,如果鎖被釋放,加鎖,否則,返回false。
template <class _Rep, class _Period>
bool try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) { return _M_try_lock_for(__rtime); }
//等待鎖,在某個時刻到達之前,如果鎖被釋放,加鎖,否則,返回false
template <class _Clock, class _Duration>
bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) { return _M_try_lock_until(__atime); }

lock_guard

//構造函數
 explicit lock_guard(mutex_type& __m) : _M_device(__m)   { _M_device.lock(); }
 lock_guard(mutex_type& __m, adopt_lock_t) noexcept : _M_device(__m)   { } // calling thread owns mutex
lock_guard(const lock_guard&) = delete;
 //析構函數
  ~lock_guard()   { _M_device.unlock(); }

個人理解:類似於智能指針,在生命週期結束時,析構,能夠自動解鎖,不需要手動解鎖,提供了一定的安全性。

unique_lock

//構造函數
unique_lock() noexcept  : _M_device(0), _M_owns(false)  { }
//構造函數,只允許顯示調用
explicit unique_lock(mutex_type& __m) : _M_device(std::__addressof(__m)), _M_owns(false) { 	lock(); 	_M_owns = true;  }
//構造函數,無互斥所有權
unique_lock(mutex_type& __m, defer_lock_t) noexcept: _M_device(std::__addressof(__m)), _owns(false){ }
//構造函數,嘗試獲得鎖的所有權,而不阻塞
 unique_lock(mutex_type& __m, try_to_lock_t)  : _M_device(std::__addressof(__m)), M_owns(_M_device->try_lock()) { }
//構造函數,擁有互斥鎖所有權
unique_lock(mutex_type& __m, adopt_lock_t) noexcept : _M_device(std::__addressof(__m)), M_owns(true){
// XXX calling thread owns mutex
}
//析構函數
~unique_lock() { if (_M_owns) unlock();}
//鎖
void lock();
//嘗試鎖
bool try_lock();
//等待
bool try_lock_until();
bool try_lock_for();
//解鎖
void unlock();
//交換所有權
void swap(unique_lock& __u);
//釋放
 mutex_type* release();
 //返回鎖狀態
  bool  owns_lock();
  //獲取鎖
 mutex_type* mutex() const noexcept { return _M_device; }

個人理解:對鎖對象的控制權,百度來的,通用互斥包裝器,允許“延遲鎖定,鎖定的有限嘗試、遞歸鎖定、所有權轉移和條件變量一同使用”,unique_lock 比 lock_guard 使用更加靈活,功能更加強大。但是使用unique_lock 需要付出更多的時間成本、性能成本。

std::condition_variable

std::condition_variable 條件變量,性能消耗小於std::mutex,對於線程同步,效率高於 std::mutex。std::conditon_variable 有兩個接口 wait(),可以是線程處與休眠狀態,另一個就是notify_one(),喚醒處於wait中的其中一個條件變量,(可能當時有很多條件變量處於wait狀態)。notify_all(),喚醒所有處於wait狀態的條件。

//構造函數
condition_variable() noexcept;
condition_variable(const condition_variable&) = delete;
//析構函數
~condition_variable() noexcept;
//喚醒單個線程
void notify_one() noexcept;
//喚醒所有線程
void notify_all() noexcept;
//休眠函數
void wait(unique_lock<mutex>& __lock) noexcept;
void wait(unique_lock<mutex>& __lock, _Predicate __p) { while (!__p()) wait(__lock);}
//休眠函數,等待時間點,線程收到通知或者指定時間點abs_time超時之前,線程都會處於阻塞狀態,超時或者被喚醒,返回
cv_status wait_until(unique_lock<mutex>& __lock, const chrono::time_point<__clock_t, _Duration>& __atime) { return __wait_until_impl(__lock, __atime); }
cv_status wait_until(unique_lock<mutex>& __lock,const chrono::time_point<_Clock, _Duration>& __atime)
{
	// DR 887 - Sync unknown clock to known clock.
	const typename _Clock::time_point __c_entry = _Clock::now();
	const __clock_t::time_point __s_entry = __clock_t::now();
	const auto __delta = __atime - __c_entry;
	const auto __s_atime = __s_entry + __delta;
	return __wait_until_impl(__lock, __s_atime);
} 
bool wait_until(unique_lock<mutex>& __lock,const chrono::time_point<_Clock, _Duration>& __atime,
_Predicate __p) { 	while (!__p()) 	if (wait_until(__lock, __atime) == cv_status::timeout) 	return __p(); 	
return true;}
//線程休眠,加了時間限制,在超時之前,處於休眠狀態,如果超時或者被喚醒,wait_for 返回
cv_status wait_for(unique_lock<mutex>& __lock,  const chrono::duration<_Rep, _Period>& __rtime)
{ return wait_until(__lock, __clock_t::now() + __rtime); }
bool wait_for(unique_lock<mutex>& __lock,  const chrono::duration<_Rep, _Period>& __rtime,
  _Predicate __p){ return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章