c++11 新標準中引入了四個標頭檔案來支援多執行緒程式設計,他們分別是,
,
,
和
。
(1)執行緒私有的資源
執行緒id,暫存器(cpu進行計算必須),棧,優先順序排程策略...
為什麼使用執行緒:
執行緒共享檔案和記憶體簡單,程序共享比較複雜;
執行緒的上下文切換消耗資源比程序少;
執行緒的cpu利用率更高
程序是程式之間的併發執行,執行緒是同一程式的片段之間併發執行;
(2)多執行緒中鎖的種類
互斥鎖(mutex):pthread_mutex_t型別,支援以下幾種方法:
pthread_mutex_lock(pthread_mutex_t* mutex);
pthread_mutex_trylock(pthread_mutex_t* mutex);
pthread_mutex_unlock(pthread_mutex_t* mutex);
pthread_mutex_timelock(pthread_mutex_t* mutex, time)
遞迴鎖:支援遞迴呼叫
讀寫鎖(共享互斥鎖):pthread_rwlock_t型別,支援以下幾種方法:
pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);
pthread_rwlock_wrlock(
pthread_rwlock_t* rwlock);
pthread_rwlock_unlock(
pthread_rwlock_t* rwlock);
自旋鎖:自旋等待,當鎖被其他執行緒占用時,一直忙等(不停嘗試獲取)阻塞;
而互斥鎖會投入睡眠。(下次喚醒的時候伴隨著排程成本)
適用情況:鎖持有時間短,不想在重新排程上花費時間
(3)執行緒建立:
c語言:
pthread_create函式,傳入函式指標;
c++:
①函式指標:thread t1(func,args[1],args[2]....);
②函式物件:
先將func宣告成乙個物件,引數為其成員變數,operator()過載,就可以呼叫:
thread t1(func(args[1],args[2]...));
(4)執行緒終止:
如果程序呼叫了exit,那麼該程序的所有執行緒都會終止;
linux中線程終止方式:
①啟動函式中返回
②被其他執行緒取消
③呼叫pthread_exit
但是在c++標準中,沒有執行緒之間互相終止的機制,乙個執行緒要想終止另外乙個執行緒,可以通過設定乙個共享變數,然後讓另外乙個執行緒定期檢查該變數值,實現兩者之間的通訊。
呼叫join函式可以獲取乙個執行緒的終止狀態,該函式會阻塞直到該執行緒終止
(5)如何從執行緒中獲取結果
①通過傳入結果變數引用或者指標
②使用future
(6)c++中互斥體類的使用
非定時互斥體:std::mutex類和std::recursive_mutex(遞迴鎖)
這兩個類支援:lock()、try_lock()、unlock()方法
定時互斥體:std::timed_mutex類、std::recursive_timed_mutex和std::shared_timed_mutex
定時互斥體都支援方法:try_lock_for(time),在給定時間內獲得鎖,超時返回false
特別的,讀寫鎖shared_timed_mutex除了支援上面的方法取得獨佔許可權之外,還能獲得共享擁有權:
lock_shared()、try_lock_shared()、unlock_shared()...
(7)c++鎖類的使用
鎖類是可選的(使用鎖類更加安全),為了更加方便的獲得、釋放互斥體上的鎖(raii自動析構時釋放資源,異常的時候能夠釋放)
std::lock_guard、std::unique_lock和std::shared_lock
鎖類接受乙個互斥體類物件進行構造,在該互斥體上進行鎖操作
lock_guardlock(mmutex);//構造鎖類,阻塞直至獲得mmutex上的鎖
lock的使用:
unique_locklock1( from.mmutex, defer_lock );//defer_lock表示延遲加鎖,此處只管理mutex
unique_locklock2( to.mmutex, defer_lock );
lock( lock1, lock2 );//lock一次性鎖住多個mutex防止deadlock
(8)避免死鎖的方法
①控制加鎖的順序,所有執行緒按照相同順序加鎖(要求事先知道將要用到的鎖)
②加鎖時限,獲取鎖的時候加上時限,如果超時(有可能死鎖了),放棄獲取該鎖,並釋放已有的鎖,一段時間之後再次嘗試
(9)條件變數——一種顯式的執行緒間通訊
條件本身由互斥量保護,c++11中有兩類條件變數:
①condition_variable:等待unique_lock,支援的方法如下:
notify_one();喚醒等待該條件變數執行緒中的乙個;
notify_all();喚醒所有
wait(unique_lock& lk);呼叫執行緒已經獲得lk的鎖,呼叫該方法會呼叫lk.unlock(),阻塞等待通知,直至另外乙個執行緒呼叫notify_one()或者notify_all()
還可以給wait函式乙個時間期限,在該期限之後解除阻塞
②condition_variable_any:等待任意鎖物件
(10)執行緒數量
對於計算密集型任務,在擁有ncpu個處理器的系統上,當執行緒池大小為n+1時,通常能實現最優的利用率,(即當計算密集型任務偶爾由於頁缺失故障或者其他原因而暫停時,這個額外的現執行緒也能夠確保cpu的時鐘週期不會被浪費。)
(11)生產者消費者模型
基於條件變數同步如下:
#include #include #include #include #include #include #include using namespace std;
mutex mtx; //互斥鎖
const int buffersize = 10; //緩衝區的大小
condition_variable not_full; //非滿條件變數
condition_variable not_empty; //非空條件變數
queuebuf;
int data = 0 ;
void produce()
}int main()
for (int i = 5; i < 10; i++)
for (auto& t : threads)
return 0;
}
(12)
銀行家演算法——一種死鎖避免演算法
安全序列是指乙個程序序列是安全的,即對於每乙個程序pi(1≤i≤n),它以後尚需要的資源量不超過系統當前剩餘資源量與所有程序pj (j < i )當前占有資源量之和。(即在分配過程中,不會出現某一程序後續需要的資源量比其他所有程序及當前剩餘資源量總和還大的情況)
注:存在安全序列則系統是安全的,如果不存在則系統不安全,但不安全狀態不一定引起死鎖。
(13)多執行緒面試題
為什麼要用多執行緒?充分發揮多核的優勢。
單核cpu下的多執行緒。防止io阻塞,所以在io密集型作業中,多執行緒還是要快。但是,如果是cpu計算密集,由於執行緒環境切換,可能會帶來額外的消耗。
面試題 多執行緒程式設計
題目 四個執行緒 t1,t2,t3,t4,向 4 個檔案中寫入資料,t1 只能寫入 1,t2 只能寫入 2,t3 只能寫 入 3,t4 只能寫入 4,對 4 個檔案 a,b,c,d 寫入如下內容 a 123412341234.b 234123412341.c 341234123412.d 41234...
面試題 多執行緒程式設計
題目 四個執行緒 t1,t2,t3,t4,向 4 個檔案中寫入資料,t1 只能寫入 1,t2 只能寫入 2,t3 只能寫 入 3,t4 只能寫入 4,對 4 個檔案 a,b,c,d 寫入如下內容 a 123412341234.b 234123412341.c 341234123412.d 41234...
多執行緒程式設計面試題
衝擊大廠必備 第一種實現方法,使用wait notify方法實現 public static void main string args char arr2 object o newobject new thread catch exception e start new thread catch ...