1. 程式人生 > >C++14:多執行緒

C++14:多執行緒

//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.