1. 程式人生 > >Boost執行緒學習

Boost執行緒學習

//本文參考部落格
//http://www.cppblog.com/toMyself/archive/2010/09/22/127347.html
//開發環境 Visual Studio 2015
//boost16.8,下面是下載地址,有編譯好的動態庫,安裝好後,在工程檔案裡引入標頭檔案和庫檔案
//https://sourceforge.net/projects/boost/files/boost-binaries/1.68.0/

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/tss.hpp>
#include <boost/thread/once.hpp>
#include <boost/bind.hpp>
#include <iostream>

void hello()
{
    std::cout << "Hello, I'm a thread!" << std::endl;
}

// 第一種方式:最簡單方法
int main_01(int argc, char* argv[])
{
    boost::thread t1(&hello);
    t1.join();


    //1. system是C標準庫的, 是子程序執行shell解釋command,可以在VisualStudio裡執行
    //2. 如果編譯好可執行程式,可直接在cmd命令列裡執行,註釋掉system("pause");這一行,推薦用這種方式
    system("pause");

     return 0;
}

//第二種方式:複雜型別物件作為引數來建立執行緒
// 結構中也可以定義操作符

boost::mutex io_mutex;
// count是一個結構

struct count
{
    //結構中提供了建構函式,因此要使用建構函式進行初始化
    //關於建構函式參考
    //https://msdn.microsoft.com/zh-cn/library/s16xw1a8.aspx
    //下面的建構函式利用引數初始化成員變數,單個:就是訪問成員變數的意思
    //前面的id是引數,臨時變數,後面的id是結構的成員變數
    count(int id) : id(id) { }
    void operator()()
    {
        for (int i = 0; i < 10; ++i)
        {
            boost::mutex::scoped_lock lock(io_mutex);
            std::cout << id << ": " << i << std::endl;
        }
    }
    int id;//預設為public
    //如今的struct和class沒啥兩樣,只是struct預設是public,class預設是private
};

int main_02(int argc, char* argv[])
{
    count c1(1);
    std::cout << c1.id << std::endl;
    boost::thread thrd1(count(1));
    boost::thread thrd2(count(2));
    thrd1.join();
    thrd2.join();
    return 0;
}


//第三種方式:在類內部建立執行緒
//(1)類內部靜態方法啟動執行緒
class StaticHelloWorld
{
    //在這裡start()和hello()方法都必須是static方法
public:
    static void hello()
    {
        std::cout << "Hello world, I'm a thread in HelloWorld Class!" << std::endl;
    }
    static void start()
    {
        boost::thread thrd(hello);
        thrd.join();
    }
};

//如果要執行這個,把main_31改為main
//因為只能有一個main函式
int main_31(int argc, char* argv[])
{
    StaticHelloWorld::start();
    return 0;
}

//(2)如果要求start()和hello()方法不能是靜態方法則採用下面的方法建立執行緒:
class BindHelloWorld
{
public:
    void hello()
    {
        std::cout << "Hello world, I'm a thread! use bind method" << std::endl;
    }
    void helloWithParamter(int i)
    {
        std::cout << "Hello world, I'm a thread! use bind method with parameter: "<< i << std::endl;
    }
    void start()
    {
        //bind用來向一個函式(或函式物件)繫結某些引數
        //bind的返回值是一個函式物件
        //參考博文
        //https://www.cnblogs.com/blueoverflow/p/4740093.html
        //https://www.boost.org/doc/libs/1_66_0/libs/bind/doc/html/bind.html
        //https://www.jianshu.com/p/30e79d2a8f7d

        //這個我不知道怎麼定義,只能先用auto
        auto f = boost::bind(&BindHelloWorld::hello, this);
        
        //將這個函式物件傳遞給執行緒
        boost::thread thrd(f);
        thrd.join();
    }
};

int main_32(int argc, char* argv[])
{
    BindHelloWorld hello;
    hello.start();
    return 0;
}

//(3)在Singleton模式內部建立執行緒:
//第四種方法:用類內部函式在類外部建立執行緒
//這兩種方式太複雜,懶得折騰了


//互斥體
//1. 一個互斥體一次只允許一個執行緒訪問共享區。當一個執行緒想要訪問共享區時,首先要做的就是鎖住(lock)互斥體。
//2. Boost執行緒庫支援兩大類互斥體,包括簡單互斥體(simple mutex)和遞迴互斥體(recursive mutex)。
//   有了遞迴互斥體,單個執行緒就可以對互斥體多次上鎖,當然也必須解鎖同樣次數來保證其他執行緒可以對這個互斥體上鎖。
//3. Boost執行緒庫提供的互斥體型別:
//     boost::mutex
//     boost::try_mutex
//     boost::timed_mutex
//     boost::recursive_mutex
//     boost::recursive_try_mutex
//     boost::recursive_timed_mutex
//     boost::shared_mutex
//
//4. mutex類採用Scope Lock模式實現互斥體的上鎖和解鎖。即建構函式對互斥體加鎖,解構函式對互斥體解鎖。
//5. 對應現有的幾個mutex匯入了scoped_lock,scoped_try_lock,scoped_timed_lock.
//6. scoped系列的特色就是析構時解鎖,預設構造時加鎖,這就很好的確定在某個作用域下某執行緒獨佔某段程式碼。

//條件變數
//1. 有的時候僅僅依靠鎖住共享資源來使用它是不夠的。有時候共享資源只有某些狀態的時候才能夠使用。
//   比方說,某個執行緒如果要從堆疊中讀取資料,那麼如果棧中沒有資料就必須等待資料被壓棧。這種情
//   況下的同步使用互斥體是不夠的。另一種同步的方式--條件變數,就可以使用在這種情況下。

const int BUF_SIZE = 10;
const int ITERS = 100;

class buffer
{
public:
    typedef boost::mutex::scoped_lock scoped_lock;
    buffer() : p(0), c(0), full(0) {}

    void put(int m)
    {
        scoped_lock lock(mutex);
        if (full == BUF_SIZE)
        {
            {
                boost::mutex::scoped_lock lock(io_mutex);
                std::cout << "Buffer is full. Waiting..." << std::endl;
            }
            while (full == BUF_SIZE)
                cond.wait(lock);
        }
        buf[p] = m;
        p = (p + 1) % BUF_SIZE;
        ++full;
        cond.notify_one();
    }

    int get()
    {
        scoped_lock lk(mutex);
        if (full == 0)
        {
            {
                boost::mutex::scoped_lock lock(io_mutex);
                std::cout << "Buffer is empty. Waiting..." << std::endl;
            }
            while (full == 0)
                cond.wait(lk);
        }
        int i = buf[c];
        c = (c + 1) % BUF_SIZE;
        --full;
        cond.notify_one();
        return i;
    }

private:
    boost::mutex mutex;
    boost::condition cond;
    unsigned int p, c, full;
    int buf[BUF_SIZE];
};


buffer buf;
void writer()
{
    for (int n = 0; n < ITERS; ++n)
    {
        {
            boost::mutex::scoped_lock lock(io_mutex);
            std::cout << "sending: " << n << std::endl;
        }
        buf.put(n);
    }
}

void reader()
{
    for (int x = 0; x < ITERS; ++x)
    {
        int n = buf.get();
        {
            boost::mutex::scoped_lock lock(io_mutex);
            std::cout << "received: " << n << std::endl;
        }
    }
}

int main_04(int argc, char* argv[])
{
    boost::thread thrd1(&reader);
    boost::thread thrd2(&writer);
    thrd1.join();
    thrd2.join();
    return 0;
}


//執行緒區域性儲存
//2018.12.11(不懂)
//函式的不可重入
//Boost執行緒庫提供了智慧指標boost::thread_specific_ptr來訪問本地儲存執行緒(thread local storage)。

boost::thread_specific_ptr<int> ptr;
struct count_local
{
    count_local(int id) : id(id) { }
    void operator()()
    {
        if (ptr.get() == 0)
        {
            ptr.reset(new int(0));
        }

        for (int i = 0; i < 10; ++i)
        {
            (*ptr)++; // 往自己的執行緒上加
            boost::mutex::scoped_lock lock(io_mutex);
            std::cout << id << ": " << *ptr << std::endl;
        }
    }
    int id;
};

int main_05(int argc, char* argv[])
{
    boost::thread thrd1(count(1));
    boost::thread thrd2(count(2));
    thrd1.join();
    thrd2.join();
    return 0;
}


//僅執行一次的例程
//1. 如何使得初始化工作(比如說建構函式)是執行緒安全的。
//2. “一次實現”(once routine)。“一次實現”在一個應用程式只能執行一次。
//3. Boost執行緒庫提供了boost::call_once來支援“一次實現”,
//   並且定義了一個標誌boost::once_flag,一個初始化這個標誌的巨集 BOOST_ONCE_INIT。

int i = 0;
boost::once_flag flag = BOOST_ONCE_INIT;
void init()
{
    ++i;
}

void thread()
{
    boost::call_once(&init, flag);
}

int main(int argc, char* argv[])
{
    boost::thread thrd1(&thread);
    boost::thread thrd2(&thread);// 這個執行不到了
    thrd1.join();
    thrd2.join();
    std::cout << i << std::endl;
    return 0;
}