日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++ boost多线程学习(一)

發布時間:2023/12/1 c/c++ 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++ boost多线程学习(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本次學習相關資料如下:
Boost C++ 庫 第 6 章 多線程(大部分代碼的來源)
Boost程序庫完全開發指南 - 深入C++“準”標準庫 第三版 羅劍鋒著

頭文件:

#include <stdio.h> #include <string.h> #include <boost\version.hpp> #include <boost\config.hpp> #include <iostream> #include <boost\thread.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/cstdint.hpp> #include <cstdlib> #include <vector> #include <random>

首先是如何創建簡單的多線程:

int sum = 0;void f_mutex(unsigned int no) {for (int i = 0; i < 10; i++) {sum++;std::cout << "我是線程" << no << ": sum 為" << sum << std::endl;} }int main() {std::cout << boost::thread::hardware_concurrency() << std::endl;//這個可以用來顯示CPU內核數,就是可以并行的線程數量std::cout << "程序開始" << std::endl;boost::thread a(f_metex,1); //第一個參數是線程要執行的函數,后面是函數所需要的參數boost::thread b(f_metex,2);a.join(); //等待線程結束,如果沒有這個的話主線程一下就結束了,子線程也沒了b.join();return 0; }

上面的打印可能會出問題,sum的值不一定就是20,因為cpu在任意時刻都有可能切換線程,當1號線程讀取出sum的值,準備加1的時候,cpu可能會切換到2號線程,讀取出sum的值并加1,然后再切換回1號線程,這時候1號線程加1的值就不正確了。

所以要控制這個共享資源,出現了互斥量這樣的內容。

boost::mutex mu; //這個是互斥量void f_mutex(unsigned int no) {for (int i = 0; i < 10; i++) {mu.lock(); //上鎖了,這樣就算切換了線程,發現上鎖了也不能繼續往下執行sum++;std::cout << "我是線程" << no << ": sum 為" << sum << std::endl;mu.unlock(); //執行完后解鎖,這樣其他線程就可以執行了} }

這個很好理解,因為有一個線程進入了臨界區,所以其他線程必須等待臨界區的訪問結束后才能進入,所以程序能夠正常打印sum為20

當然如果臨界區里面出現了異常,導致沒有正常解鎖,是不是就會影響到其他線程進入臨界區呢?所以我們可以使用lock_guard來解決問題。

std::default_random_engine e; //用來生成隨機數 /* 線程睡眠函數 */ void wait(int seconds) {boost::this_thread::sleep(boost::posix_time::seconds(seconds)); }void f_lock_guard() {int i;for (i = 0; i < 10; i++) {boost::lock_guard<boost::mutex> lock(mu); wait(e() % 2); //這個是一個sleep函數,e()就可以生成一個隨機數了。sum++;std::cout << "我是線程" << boost::this_thread::get_id() << ": sum 為" << sum << std::endl; //這個get_id可以打印線程號,不需要傳入參數來區分線程了。 }std::cout << "我是線程" << boost::this_thread::get_id() << ",我結束了。i :" << i << std::endl; }int main() {std::cout << boost::thread::hardware_concurrency() << std::endl;//這個可以用來顯示CPU內核數,就是可以并行的線程數量std::cout << "程序開始" << std::endl;boost::thread a(f_lock_guard); //這里改動了,不再需要參數了boost::thread b(f_lock_guard);a.join(); //等待線程結束,如果沒有這個的話主線程一下就結束了,子線程也沒了b.join();return 0; }

lock_guard 這個類會在構造函數里調用mu.lock(),析構函數里調用mu.unlock(),這樣的話lock就會在離開作用域的時候調用析構函數,從而調用mu.unlock(),退出臨界區的占用。

當程序存在多個線程需要讀取資源,而只有一個線程會修改資源(即讀者-寫者問題),使用上面的方法并不能很好地實現。

先來描述一下要求:
(1)可以存在多個線程同時讀取資源;
(2)讀取資源的時候不可以修改資源;
(3)修改資源的時候不可以讀取資源;

為了滿足上面3個要求,要增加新類型的鎖。
這里f_shared_fillrandom_numbers添加隨機數,相當于寫著;
f_shared_printf_shared_count 打印隨機數和統計隨機數,相當于讀者。

boost::shared_mutex shared_mu; vector<int> random_numbers;int sum = 0; void f_shared_fill() {for (int i = 0; i < 5; ++i) {boost::unique_lock<boost::shared_mutex> lock(shared_mu); //寫鎖std::cout << "我要寫入了" << std::endl;random_numbers.push_back(e()%100);std::cout << "我寫完了" << std::endl;lock.unlock();wait(1);} }void f_shared_print() {for (int i = 0; i < 5; ++i) {wait(1);boost::shared_lock<boost::shared_mutex> lock(shared_mu); //讀鎖boost::this_thread::yield(); //放棄時間片,讓其他線程執行std::cout << "我在打印" << std::endl;std::cout << random_numbers.back() << std::endl;std::cout << "我打印完了" << std::endl;} }void f_shared_count() {for (int i = 0; i < 5; ++i) {wait(1);boost::shared_lock<boost::shared_mutex> lock(shared_mu); //讀鎖boost::this_thread::yield(); //放棄時間片,讓其他線程執行std::cout << "我在統計" << std::endl;sum += random_numbers.back();std::cout << "我統計完了" << std::endl;} }int main() {std::cout << "程序開始" << std::endl;boost::thread a(f_shared_fill);boost::thread b(f_shared_print);boost::thread c(f_shared_count);a.join();b.join();c.join();std::cout << sum << std::endl;return 0; }

注意寫鎖和讀鎖的區別。

boost::unique_lockboot::lock_guard類似,也是能夠在構造函數中鎖定,析構函數中解鎖,但比boot::lock_guard更復雜。

f_shared_fill函數執行的時候上鎖,保證其他線程無法訪問。并且在后面有個主動調用lock.unlock的主動解鎖,然后進入睡眠,保證讀者線程能夠執行。

f_shared_printf_shared_count開頭都有一個wait,用來保證f_shared_fill比他們先執行完。然后有一個釋放時間片yield,通過這個能夠更好地看出在f_shared_printf_shared_count執行的過程中,cpu能夠執行另外的讀者線程,之所以不執行f_shared_fill是因為執行yield之前已經加了讀鎖。

程序是通過wait來控制線程的執行順序,不會出現讀線程執行了2次或以上而寫線程未執行或是寫線程寫入了2次或以上而讀線程一次都未執行。

當然可以用更好的方法來解決這個問題,那就是條件變量。

void f_condition_fill() {for (int i = 0; i < 10; ++i) {std::cout << "我是線程1 "<<random_numbers.size()<<std::endl;boost::unique_lock<boost::mutex> lock(mu);random_numbers.push_back(e()%100);cond.notify_all();cond.wait(mu);} }void f_condition_print() {static int next_size = 1;for (int i = 0; i < 10; ++i) {std::cout << "我是線程2 " << random_numbers.size() << std::endl;boost::unique_lock<boost::mutex> lock(mu); while (next_size != random_numbers.size()) {cond.wait(mu);} std::cout << random_numbers.back() << std::endl;++next_size;cond.notify_all();} } int main() {std::cout << "程序開始" << std::endl;boost::thread a(f_condition_fill);boost::thread b(f_condition_print);a.join();b.join();std::cout << sum << std::endl;return 0; }

注意到這里用到的互斥量是mutex而不是shared_lock

總結

以上是生活随笔為你收集整理的c++ boost多线程学习(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。