Boost執行緒學習
阿新 • • 發佈:2018-12-11
//本文參考部落格
//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; }