創建線程
std::thread thObj(<CALLBACK>);
其中的函數可以是函數指針,函數對象,lambda函數。線程創建完成即開始運行。
#include <thread>
void thread_function(){
std::cout<<"thread function Executing"<<std::endl;
}
int main() {
std::thread threadObj(thread_function);
std::cout<<"Display From MainThread"<<std::endl;
threadObj.join();
std::cout<<"Exit of Main function"<<std::endl;
return 0;
}
使用std::thread::get_id()
和std::this_thread::get_id()
可以獲取線程id,其中std::thread::id
是一個對象。
等待及分離線程
std::thread th(funcPtr);
// Some Code
th.join();
std::thread th(funcPtr);
// Some Code
th.detach();
使用join
等待創建的線程結束,detach
使線程分離。
對同一個線程連續調用join
或detach
會造成崩潰。因此在調用前最好先使用threadObj.joinable()
判斷線程當前狀態。
創建一個線程後必須對其調用join
或detach
,因爲std::thread
的虛構函數會進行檢查如果仍是joinable
狀態則終止進程。
線程傳參
在創建std::thread
對象時增加函數需要的參數即可。如果要傳引用需要使用std::ref()
。
如果要創建對象成員函數的線程:
std::thread threadObj(&Class::MemberFunction,&Class,arg);
競爭條件,鎖
爲了避免多線程對共享數據操作產生錯誤,對共享數據進行更改時使用鎖。
#include<iostream>
#include<thread>
#include<vector>
#include<mutex>
class Wallet{
int mMoney;
std::mutex mutex;
public:
Wallet() :mMoney(0){}
int getMoney() { return mMoney; }
void addMoney(int money){
mutex.lock();
for(int i = 0; i < money; ++i){
mMoney++;
}
mutex.unlock();
}
};
爲了避免忘記解鎖,可以使用lock_guard
。
class Wallet{
int mMoney;
std::mutex mutex;
public:
Wallet() :mMoney(0){}
int getMoney() { return mMoney; }
void addMoney(int money){
std::lock_guard<std::mutex> lockGuard(mutex);
for(int i = 0; i < money; ++i){
mMoney++;
}
}
};
條件變量
#include <iostream>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
using namespace std::placeholders;
class Application{
std::mutex m_mutex;
std::condition_variable m_condVar;
bool m_bDataLoaded;
public:
Application(){
m_bDataLoaded = false;
}
void loadData(){
// Make This Thread sleep for 1 Second
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout<<"Loading Data from XML"<<std::endl;
// Lock The Data structure
std::lock_guard<std::mutex> guard(m_mutex);
// Set the flag to true, means data is loaded
m_bDataLoaded = true;
// Notify the condition variable
m_condVar.notify_one();
}
bool isDataLoaded(){
return m_bDataLoaded;
}
void mainTask(){
std::cout<<"Do Some Handshaking"<<std::endl;
// Acquire the lock
std::unique_lock<std::mutex> mlock(m_mutex);
// Start waiting for the Condition Variable to get signaled
// Wait() will internally release the lock and make the thread to block
// As soon as condition variable get signaled, resume the thread and
// again acquire the lock. Then check if condition is met or not
// If condition is met then continue else again go in wait.
while(m_bDataLoaded!=true){
m_condVar.wait(mlock, std::bind(&Application::isDataLoaded, this));
}
std::cout<<"Do Processing On loaded Data"<<std::endl;
}
};
int main(){
Application app;
std::thread thread_1(&Application::mainTask, &app);
std::thread thread_2(&Application::loadData, &app);
thread_2.join();
thread_1.join();
return 0;
}
等待條件時首先加鎖,wait
函數內部會解鎖並阻塞進行等待,收到通知後會重新上鎖。因爲有可能被虛假喚醒,所以喚醒後需要重新檢查條件。
std::future std::promise
如果我們想要線程返回一個結果可以用future
和promise
來實現。future
保存一個我們將來想要獲取的值,而promise
與future
相關聯用來設置future
的值。
#include <iostream>
#include <thread>
#include <future>
void initiazer(std::promise<int> * promObj){
std::cout<<"Inside Thread"<<std::endl; promObj->set_value(35);
}
int main(){
std::promise<int> promiseObj;
std::future<int> futureObj = promiseObj.get_future();
std::thread th(initiazer, &promiseObj);
std::cout<<futureObj.get()<<std::endl;
th.join();
return 0;
}
通過創建promise
然後取得其關聯的future
,將promise
傳遞給其他線程,在其他線程中調用set_value
設置future
的值,之後調用get
取得值。
std::async
template <class Fn, class... Args>
future<typename result_of<Fn(Args...)>::type> async (launch policy, Fn&& fn, Args&&... args);
async
是一個函數模板,可以接收一個函數並且異步執行。它會返回一個future
用來獲取返回值。
launch policy
有兩種
std::launch::async 起一個新線程來執行,異步。
std::launch::deferred 在其他線程調用
future
的get
時再執行,同步。
std::future<std::string> resultFromDB = std::async(std::launch::async, fetchDataFromDB, "Data");
// Do Some Stuff
//Fetch Data from DB
// Will block till data is available in future<std::string> object.
std::string dbData = resultFromDB.get();
async
首先創建一個thread
和promise
對象,然後返回其關聯的future
對象。
std::packaged_task<>
packaged_task<>
保存一個函數和需要返回的值。只可移動,不可拷貝。
#include <iostream>
#include <thread>
#include <future>
#include <string>
// Fetch some data from DB
std::string getDataFromDB( std::string token){
// Do some stuff to fetch the data
std::string data = "Data fetched from DB by Filter :: " + token;
return data;
}
int main(){
// Create a packaged_task<> that encapsulated the callback i.e. a function
std::packaged_task<std::string (std::string)> task(getDataFromDB);
// Fetch the associated future<> from packaged_task<>
std::future<std::string> result = task.get_future();
// Pass the packaged_task to thread to run asynchronously
std::thread th(std::move(task), "Arg");
// Join the thread. Its blocking and returns when thread is finished.
th.join();
// Fetch the result of packaged_task<> i.e. value returned by getDataFromDB()
std::string data = result.get();
std::cout << data << std::endl;
return 0;
}
async
相當於封裝了packaged_task<>
,promise
,future
。