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.mzph.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…