C++11多線程

創建線程

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使線程分離。
對同一個線程連續調用joindetach會造成崩潰。因此在調用前最好先使用threadObj.joinable()判斷線程當前狀態。
創建一個線程後必須對其調用joindetach,因爲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

如果我們想要線程返回一個結果可以用futurepromise來實現。future保存一個我們將來想要獲取的值,而promisefuture相關聯用來設置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 在其他線程調用futureget時再執行,同步。

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首先創建一個threadpromise對象,然後返回其關聯的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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章