C++14:多執行緒
阿新 • • 發佈:2019-01-06
//Lambda表示式:[]捕獲列表()引數列表{}函式主體
/*
1.[var]表示值傳遞方式捕捉變數var;
2.[=]表示值傳遞方式捕捉所有父作用域的變數(包括this);
3.[&var]表示引用傳遞捕捉變數var;
4.[&]表示引用傳遞方式捕捉所有父作用域的變數(包括this);
5.[this]表示值傳遞方式捕捉當前的this指標
*/
多執行緒加鎖
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
std::mutex g_lock; //獨佔的互斥量,不能遞迴使用
void func()
{
g_lock.lock();
std::cout << "entered thread" << std::this_thread::get_id() << std::emdl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "leave thread" << std::this_thread::get_id() << std::endl ;
g_lock.unlock();
/*
std::lock_guard <std::mutex> locker(g_lock);出作用域之後自動解鎖
*/
}
int main()
{
std::thread t1(func);
std::thread t2(func);
std::thread t3(func);
t1.join();
t2.join();
t3.join();
return 0;
}
//遞迴互斥量,不帶超時功能 //用來解決統一執行緒需要多次獲取互斥量時死鎖的問題
std: :timed_mutex mutex;
void work()
{
std::chrono::milliseconds timeout(100); //超時時間 ,如果超時,休眠100毫秒,再繼續獲取超時鎖
while(true)
{
if(mutex.try_lock_for(timeout))
{
std::cout<<std::this_thread::get_id() << ":do work with the mutex" << std::endl;
std::chrono::milliseconds sleepDuration(250);
std::this_thread::sleep_for(sleepDuration);
mutex.unlock();
std::this_thread::sleep_for(sleepDuration);
}
else
{
std::cout << std::this_thread::get_id() << ": do work without mutex" << std::endl;
std::chrono::milliseconds sleepDuration(100);
std::this_thread::sleep_for(sleepDuration);
}
}
}
/*條件變數:
C++11提供兩種條件變數:condition_variable配合std::unique_lock<std::mutex> 進行wait操作
condition_variable_any 和任意帶有lock、unlock語義的mutex搭配使用,比較靈活,但效率比condition_variable差一些
1.擁有條件變數的執行緒獲取互斥量
2.迴圈檢查某個條件,如果條件不滿足,則阻塞直到條件滿足,如果條件滿足,則向下執行
3.某個執行緒滿足條件執行完之後呼叫notify_one或者notify_all喚醒一個或者所有的等待執行緒。*/
/*
這個同步佇列在沒有滿的情況下,可以插入資料,如果滿了,則會呼叫m_notFull阻塞等待,待消費執行緒取出資料之後發一個未滿的通知
,然後前面阻塞的執行緒就會喚醒繼續往下執行;如果佇列為空,就不能取資料,會呼叫m_notEmpty條件變數阻塞,等待插入資料的執行緒發出不為空
的通知時,才能往下繼續執行
*/
#include <mutex>
#include <thread>
#include <condition_variable>
template<typename T>
class SyncQueue
{
bool isFull() const
{
return m_queue.size() == m_maxSize;
}
bool isEmpty() const
{
return m_queue.empty();
}
public:
SyncQueue(int maxSize) : m_maxSize(maxSize)
{
}
void Put(const T& x)
{
std::lock_guard<std::mutex> locker(m_mutex);
while(isFull())
{
cout << "快取區滿了,需要等待"<<endl; //while迴圈等同於 m_notFull.wait(locker,[this]{return !isFull();});
m_notFull.wait(m_mutex); //條件變數會先檢查判斷式是否滿足條件,如果滿足條件,則重新獲取mutex,然後結束wait
} //,繼續往下執行;如果不滿足條件,釋放mutex,將執行緒置為waiting狀態,繼續等待
m_queue.push_back(x);
m_notEmpty.notify_one();
}
void Take(T& x)
{
std::lock_guard<std::mutex> locker(m_mutex);
while(isEmpty())
{
cout<<"快取區空了,需要等待" <<endl;
m_notEmpty.wait(m_mutex);
}
x = m_queue.front();
m_queue.pop_front();
m_notFull.notify_one();
}
bool Empty()
{
std::lock_guard<std::mutex> locker(m_mutex);
return m_queue.empty();
}
bool Full()
{
std::lock_guard<std::mutex> locker(m_mutex);
return m_queue.size() == m_maxSize;
}
size_t Size()
{
std::lock_guard<std::mutex> locker(m_mutex);
return m_queue.size();
}
int Count()
{
return m_queue.size();
}
private:
std::list<T> m_queue; //緩衝區
std::mutex m_mutex;
std::condition_variable_any m_notEmpty; //不為空的條件變數
std::condition_variable_any m_notFull; //沒有滿的條件變數
int m_maxSize;//同步佇列最大的size
}
/把std::lock_guard改成std::unique_lock,把std::condition_variable_any改為condition_variable/
#include <thread>
#include <condition_variable>
#include <mutex>
#include <list>
#include <iostream>
using namespace std;
template <typename T>
class SimpleSyncQueue
{
public:
SimpleSyncQueue()
{
}
~SimpleSyncQueue();
void Put(const T& x)
{
std::lock_guard<std::mutex> locker(m_mutex);
m_queue.push_back(x);
m_notEmpty.notify_one();
}
void Take(T& x)
{
std::unique_lock<std::mutex> locker(m_mutex);
m_notEmpty.wait(locker,[this]{return !m_queue.empty()});
x = m_queue.front();
m_queue.pop_front();
}
bool Empty()
{
std::lock_guard<std::mutex> locker(m_mutex);
return m_queue.empty();
}
size_t Size()
{
std::lock_guard<std::mutex> locker(m_mutex);
return m_queue.size();
}
private:
std::list<T> m_queue;
std::mutex m_mutex;
std::condition_variable m_notEmpty;
};
//用mutex實現的計時器
struct Counter
{
int value;
std::mutex mutex;
void increment()
{
std::lock_guard<std::mutex> lock(mutex);
++value;
}
void decrement()
{
std::lock_guard<std::mutex> lock(mutex);
--value;
}
int get()
{
return value;
}
};
//用原子變數實現的計時器就不需要互斥變數
#include <atomic>
struct AtomicCounter
{
std::atomic<int> value;
void increment()
{
++value;
}
void decrement()
{
--value;
}
int get()
{
return value.load();
}
};
//call_once/once_flag的使用 保證多執行緒中的函式只被呼叫一次
#include <iostream>
#include <thread>
#include <mutex>
std::once_flag flag;
void do_once()
{
std::call_once(flag,[](){std::cout << "called once" << endl;});
}
int main()
{
std::thread t1(do_once);
std::thread t2(do_once);
t1.join();
t2.join();
return 0;
}
//獲取執行緒函式返回值的類 std::future
//get_future : 返回具有和承諾相同的“關聯的非同步狀態”的將來的物件
//通過查詢 future 的狀態來或取非同步操作的結果,future_status有三種狀態:Deferred:還沒開始,Ready:非同步操作已經完成,Timeout:非同步操作超時
//查詢frture狀態
std::future_status status;
do{
status = future.wait_for(std::chrono::seconds(1));
if(status == std::future_status::deferred)
{
std::cout << "未開始\n" << endl;
}
else if(status == std::future_status::timeout)
{
std::cout << "操作超時\n" << endl;
}
else if(status == std::future_status::ready)
{
std::cout << "完成\n" << endl;
}
}while(status != std::future_status::ready);
//獲取future結果3種方式:get\wait\wait_for.get是等待非同步操作結束並返回結果。
//wait只是等待非同步操作完成,wait_for是超時等待返回結果
//協助執行緒賦值的類std::promise
//為獲取執行緒函式中的某個值提供便利,線上程函式中為外面傳進來的promise賦值,線上程函式執行完成之後就可以通過promise的future獲取該值。
//取值是間接的通過promise內部提供的futrue來獲取的
std::promise<int> pr;
std::thread t([](std::promise<int>& p){p.set_value_at_thread_exit(9);},std::ref(pr));
std::future<int> f = pr.get_futrue();
auto r = f.get();
//可呼叫物件的包裝類std::packaged_task
//包裝了一個可呼叫物件的包裝類,將函式和future繫結,儲存一個函式。
//std::ref 用於包裝按引用傳遞的值。
//std::cref 用於包裝按const 引用傳遞的值。
std::packaged_task<int ()> task([](){return 7;});
std::thread t1(std::ref(task));
std::future<int> f1 = task.get_futrue();
auto r1 = f1.get();
//std::packaged_task和std::promise,內部都有一個future以便訪問非同步操作結果,std::packaged_task中包裝的是一個非同步操作,std::promise包裝的
//是一個值,因為有時候獲取執行緒中的某個值,用std::promise。有時候需要獲一個非同步操作的返回值,用std::packaged_task。
//可以將std::packaged_task非同步操作的值儲存在std::promise。
//future被promise和packaged_task用來作為非同步操作或者非同步結果儲存到std::promise,用std::future和std::shared_future來獲取呼叫的結果。
//feture是不可以拷貝,只能移動,shared_future是可以拷貝的,當需要將future放到容器中則需要用shared_future。
#include <iostream>
#include <utility> //以幫助構建和管理的物件, <utility>標題將自動包含通過 <map> 要幫助管理其鍵/值對鍵入的元素。
#include <future>
#include <thread>
int func (int x)
{
return x+2;
}
int main()
{
std::packaged_task<int (int)> tak(func);
std::future<int> fut = tak.get_futrue(); //獲取feture
std::thread(std::move(tak),2).detach(); //task作為執行緒函式,std::move是將一個左值強制轉化為右值引用,繼而通過右值引用該值
//detach呼叫之後,目標執行緒就成為了守護執行緒,駐留後臺執行,與之關聯的std::thread物件失去對目標執行緒的關聯,
//無法再通過std::thread物件取得該執行緒的控制權。當執行緒主函式執行完之後,執行緒就結束了,執行時庫負責清理與該執行緒相關的資源
int value = fut.get();//等待task完成並且或許結果
std::cout << "this future is " << value << endl;
std::vector<std::shared_future<int>> v;
auto f = std::async(std::launch::async,[](int a,int b){return a+b;},2,3);
v.push_back(f);
std::cout << "the shared_future result is " << v[0].get() <<endl;
return 0;
}
//this result is 4
//the shared_future result is 5
//std::async直接建立非同步的task,非同步操作返回的結果也儲存在future中,當需要獲取非同步操作結果時,只需要呼叫future.get();
//要是不想要結果,future.wait()即可。
//std::async(模式,執行緒函式,執行緒函式的引數....);模式:std::launch::async:呼叫async的時候開始建立執行緒,
//std::launch::deferred:延遲載入方式建立執行緒,直到呼叫future的get或者wait才建立執行緒
std::future<int> f1 = std::async(std::launch::async,[](){return 8;});
cout << f1.get() << endl; //output : 8
std::future<int> f2 = std::async(std::launch::async,[](){cout << 8 << endl;});
f2.wait(); //output:8
std::future<int> future = std::async(std::launch::async,[](){std::this_thread::sleep_for(std::chrono::seconds(3));
return 8;
});
std::cout << "waiting..." << endl;
std::future_status status;
do{
status = future.wait_for(std::chrono::seconds(1));
if(status == std::future_status::deferred)
{
std::cout<<"未開始\n"<<endl;
}
else if(status == std::future_status::timeout)
{
std::cout<<"超時\n"<<endl;
}
else if(status == std::future_status::ready)
{
std::cout<<"完成\n"<<endl;
}
}while(status != std::future_status::ready);
std::cout<<"result is"<<future.get()<<"\n";
這裡是我記錄的C++14特性下的多執行緒
有什麼問題請聯絡我:839505138.