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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/376302.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/376302.shtml
英文地址,請注明出處:http://en.pswp.cn/news/376302.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C#中什么是泛型

所謂泛型是指將類型參數化以達到代碼復用提高軟件開發工作效率的一種數據類型。一種類型占位符&#xff0c;或稱之為類型參數。我們知道一個方法中&#xff0c;一個變量的值可以作為參數&#xff0c;但其實這個變量的類型本身也可以作為參數。泛型允許我們在調用的時候再指定這…

敏捷自動化測試(1)—— 我們的測試為什么不夠敏捷?

測試是為了保證軟件的質量&#xff0c;敏捷測試關鍵是保證可以持續、及時的對軟件質量情況進行全面的反饋。由于在敏捷開發過程中每個迭代都會增加功能、修復缺陷或重構代碼&#xff0c;所以在完成當前迭代新增特性測試工作的同時&#xff0c;還要通過回歸測試來保證歷史功能不…

學習c++

目錄 一 、 boost庫&#xff1a; 1. 多線程 c boost多線程學習&#xff08;一&#xff09; 二 、數據庫&#xff1a; 三、socket編程&#xff1a; c socket學習&#xff08;1.1&#xff09; c socket學習&#xff08;1.2&#xff09; c socket學習&#xff08;1.3&#x…

mysql5.6與mysql5.5不同

1.編譯階段 要明白with與without的區別&#xff0c;選項值分1和0&#xff0c;或者對應為on或off&#xff0c;代表支持與不支持&#xff1b;with的1&#xff08;on&#xff09;與without的0&#xff08;off&#xff09;是同樣的&#xff0c;with的0&#xff08;off&#xff09;與…

c++ 基本排序算法學習

C實現排序算法 代碼地址 vector<unsigned int> cVec; int nSize cVec.size();1 冒泡排序 算法思路&#xff1a; 每兩兩相鄰的數值都會比較大小&#xff0c;前面比后面大的時候就交換位置&#xff0c;否則就不動。 代碼&#xff1a; void BubbleSort() {//優化&#x…

ios 程序學習

馬上著手開發iOS應用程序&#xff1a;五、提交應用與尋找信息 2013-01-11 15:36 佚名 apple.com 我要評論(0) 字號&#xff1a;T | T本文介紹了您已經學習完如何開發一個優秀的iOS應用之后&#xff0c;應該掌握的內容&#xff0c;包括將您的應用提交到App Store讓其他人下載&am…

解決SimpleButton被移除后保持OVER狀態

假設場景中有一SimpleButton叫testBtn,執行下面操作&#xff1a;1.鼠標移上testBtn&#xff0c; testBtn狀態變為OVER2.移除testBtn&#xff0c;removeChild(testBtn)3.5秒后重新添加testBtn到場景此時&#xff0c;看見testBtn還是OVER狀態。解決方法&#xff1a;1.記錄testBtn…

c++ socket學習(1.1)

本文學習相關資料&#xff1a; C/C socket編程教程 環境&#xff1a;vs2015 源碼&#xff1a;本文代碼 windows 如何創建客戶端與服務端通信&#xff1f; TCP&#xff1a; 服務端 在windows先告訴程序我們要使用哪個版本的winsock&#xff0c;成功調用了它才能繼續下去 #…

c++ socket學習(1.2)

本文學習相關資料&#xff1a; C/C socket編程教程 環境&#xff1a;vs2015 源碼&#xff1a;本文代碼 windows 如何創建客戶端與服務端通信&#xff1f; UDP&#xff1a; 這次就沒什么客戶端服務端好說了&#xff0c;UDP是沒有無連接的 所以改叫接收端和發送端吧 接收端 …

js高級功能與高級需求、高級期待

http://www.cnblogs.com/leadzen/archive/2008/02/25/1073404.html 簡單練習題&#xff1a;http://tieba.baidu.com/p/2189347922 ---------------------- scope鏈 閉包 Javascript屬性prototype node.js metaprogramming AMD、CMD機制 http://www.makumo.com/js-modules-amd-c…

synchronized同步鎖

在多線程的情況下&#xff0c;由于同一進程的多個線程共享同一片存儲空間&#xff0c;在帶來方便的同時&#xff0c;也帶來了訪問沖突這個嚴重的問題。Java語言提供了專門機制以解決這種沖突&#xff0c;有效避免了同一個數據對象被多個線程同時訪問。由于我們可以通過 private…

c++ socket學習(1.3)

本文學習相關資料&#xff1a; C/C socket編程教程 環境&#xff1a;vs2015 源碼&#xff1a;本文代碼 在這里c socket學習&#xff08;1.1&#xff09;學到了怎么樣建立TCP&#xff0c;然后通過TCP連接發送、接收信息。 但是都是一次性的&#xff0c;當時是接收信息后就結束…

一個一線城市的IT白領的生活成本:3萬/年

自從大學畢業&#xff0c;經濟獨立&#xff0c;就開始全面統計各種生活開支。仔細的去統計下&#xff0c;發現開銷還是挺大的。 定理&#xff1a;開銷越大&#xff0c;就意味著你每個月的收入必須越高。 三族鼎立節余族: 收入-開支 > 0月光族&#xff1a;收入-開支 0透支族…

android 編譯共享ccache的緩存

1. android自帶的ccache版本號(2.4版本號)過低&#xff0c;是無法支持以上的功能的&#xff0c;須要使用新版ccache。2. 最新的ccache請到http://ccache.samba.org/download.html下載3. 下載解壓之后&#xff0c;在linux底下進入ccache文件夾&#xff0c;執行:./configure./mak…

一位軟件工程師的6年總結

作者&#xff1a;成曉旭 “又是一年畢業時”&#xff0c;看到一批批學子離開人生的象牙塔&#xff0c;走上各自的工作崗位&#xff1b;想想自己也曾經意氣風發、躊躇滿志&#xff0c;不覺感嘆萬千……本文是自己工作6年的經 歷沉淀或者經驗提煉&#xff0c;希望對所有的軟件工…

c++ socket學習(1.4)

本文學習相關資料&#xff1a; C/C socket編程教程 環境&#xff1a;vs2015 源碼&#xff1a;本文代碼 前面學到了TCP怎么循環發包&#xff0c;但是TCP連接的話會出現一個問題粘包。 TCP連接接收到的數據并不是馬上讀取到內存里面的&#xff0c;而是放在緩沖區&#xff0c;讓…

mongodb中分頁顯示數據集的學習

mongodb中分頁顯示數據集的學習 這次繼續看mongodb中的分頁。首先依然是插入數據&#xff1a; 1&#xff09; db.Blog.insert( { name : "Denis", age : 20, city : "Princeton" } ) db.Blog.insert( { name : "Abe", age : 30, city : &quo…

學習編程,英語很重要!!

學會編程&#xff0c;可能不需要英語多好&#xff0c;但是學號編程&#xff0c;英語真的很重要&#xff01;&#xff01;&#xff01; 好多文檔&#xff0c;demo全是英文的&#xff0c;蛋疼&#xff0c;應許需要學習&#xff01;&#xff01;&#xff01;轉載于:https://www.cn…

c++ socket學習(1.5)

本文學習相關資料&#xff1a; C/C socket編程教程 環境&#xff1a;vs2015 源碼&#xff1a;本文代碼 這次來試一下使用TCP來傳輸文件&#xff0c;其實傳輸數據和差不多&#xff0c;就是多一個讀取文件&#xff0c;和一個寫文件而已。 服務端 int readlan 100; std::ifst…

matlab生成HEX文件-任意信號 大于64K長度

HEX文件格式不贅述&#xff0c;寫里直接放上代碼。請批評改正。 1 %%convert a signal data into hex file format2 % data format:16bit 3 % signal length: less than 2^24-14 % author: Yang Li yangli0534gmail.com5 % data:2015.01.276 7 clear all;8 close all;9 clc; 10…