一 多線程
傳統的C++(C++11之前)中並沒有引入線程這個概念,在C++11出來之前,如果我們想要在C++中實現多線程,需要藉助操作系統平台提供的API,比如Linux的<pthread.h>,或者windows下的<windows.h> 。
二 多線程的優缺點
優點:
有操作系統相關知識的應該知道,線程是輕量級的進程,每個線程可以獨立的運行不同的指令序列,但是線程不獨立的擁有資源,依賴於創建它的進程而存在。也就是説,同一進程中的多個線程共享相同的地址空間,可以訪問進程中的大部分數據,指針和引用可以在線程間進行傳遞。這樣,同一進程內的多個線程能夠很方便的進行數據共享以及通信,也就比進程更適用於併發操作。
缺點:
由於缺少操作系統提供的保護機制,在多線程共享數據及通信時,就需要程序員做更多的工作以保證對共享數據段的操作是以預想的操作順序進行的,並且要極力的避免死鎖(deadlock)。
三 多線程初體驗
代碼示例:
使用g++編譯下列代碼的方式:g++ test.cc -o test -l pthread
#include <iostream>
#include <thread>
using namespace std;
void thread_1()
{
cout<<"子線程1"<<endl;
}
void thread_2(int x)
{
cout<<"x:"<<x<<endl;
cout<<"子線程2"<<endl;
}
int main()
{
thread first ( thread_1); // 開啓線程,調用:thread_1()
thread second (thread_2,100); // 開啓線程,調用:thread_2(100)
//thread third(thread_2,3);//開啓第3個線程,共享thread_2函數。
std::cout << "主線程\n";
first.join(); //必須説明添加線程的方式
second.join();
std::cout << "子線程結束.\n";//必須join完成
return 0;
}
join與detach方式:
當線程啓動後,一定要在和線程相關聯的thread銷燬前,確定以何種方式等待線程執行結束。比如上例中的join。
- detach方式,啓動的線程自主在後台運行,當前的代碼繼續往下執行,不等待新線程結束。
- join方式,等待啓動的線程完成,才會繼續往下執行。
四 互訴鎖mutex
同一個mutex變量上鎖之後,一個時間段內,只允許一個線程訪問它。
mutex頭文件主要聲明瞭與互斥量(mutex)相關的類。mutex提供了4種互斥類型
std::mutex 最基本的 Mutex 類。
std::recursive_mutex 遞歸 Mutex 類。
std::time_mutex 定時 Mutex 類。
std::recursive_timed_mutex 定時遞歸 Mutex 類。
std::mutex 是C++11 中最基本的互斥量,std::mutex 對象提供了獨佔所有權的特性——即不支持遞
歸地對 std::mutex 對象上鎖,而 std::recursive_lock 則可以遞歸地對互斥量對象上鎖。
lock與unlock:
- lock():資源上鎖
- unlock():解鎖資源
- trylock():查看是否上鎖
代碼示例:
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex
std::mutex mtx; // mutex for critical section
void print_block (int n, char c) {
// critical section (exclusive access to std::cout signaled by locking mtx):
mtx.lock();
for (int i=0; i<n; ++i) { std::cout << c; }
std::cout << '\n';
mtx.unlock();
}
int main ()
{
std::thread th1 (print_block,50,'*');//線程1:打印*
std::thread th2 (print_block,50,'$');//線程2:打印$
th1.join();
th2.join();
return 0;
}
輸出:
**************************************************
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
lock_guard
創建lock_guard對象時,它將嘗試獲取提供給它的互斥鎖的所有權。當控制流離開lock_guard對象的作用域時,lock_guard析構並釋放互斥量。
lock_guard的特點:
- 創建即加鎖,作用域結束自動析構並解鎖,無需手工解鎖
- 不能中途解鎖,必須等作用域結束才解鎖
代碼示例:
#include <thread>
#include <mutex>
#include <iostream>
int g_i = 0;
std::mutex g_i_mutex; // protects g_i,用來保護g_i
void safe_increment()
{
const std::lock_guard<std::mutex> lock(g_i_mutex);
++g_i;
std::cout << std::this_thread::get_id() << ": " << g_i << '\n';
// g_i_mutex自動解鎖
}
int main()
{
std::cout << "main id: " <<std::this_thread::get_id()<<std::endl;
std::cout << "main: " << g_i << '\n';
std::thread t1(safe_increment);
std::thread t2(safe_increment);
t1.join();
t2.join();
std::cout << "main: " << g_i << '\n';
}
五 條件變量condition_variable
condition_variable條件變量可以阻塞(wait、wait_for、wait_until)調用的線程直到使用(notify_one或notify_all)通知恢復為止。condition_variable是一個類,這個類既有構造函數也有析構函數,使用時需要構造對應的condition_variable對象,調用對象相應的函數來實現上面的功能。