C++11多线程编程Part.2

C++11多线程服务器编程Part.1 在之前的学习过程中,关于多线程服务器编程的学习内容主要在Linux上的C语言实现,例如pthread_create,等函数,如今C++11也有很多支持多线程的函数和方法(当然环境选择Linux或者Windows都是可以的),并且更加高效和灵活,学无止境,从这次开始,进入到C++11多线程服务器编程开发的学习中。 C++11提供的的多线程编程接口 高级接口:future,async 低级接口:thr... 阅读详情

std::thread Value&Value.joinable()总是成对出现

他们的关系就像是构造函数和析构函数一样,如果创建一个线程而不去joinable这个线程,很有可能造成MainThread已经结束但是this_thread并没有结束,导致this_thread(workThread)无法正常完成工作或者无法正常退出,引发错误。
joinable的作用是询问当前线程是否已经运行完毕,如果没有运行完毕,MainThread则会在这一行继续等待,这里的等待不是while(true)这样低效的等待,而是将MainThread挂起,释放CPU资源,不会浪费资源,需要注意的是,此时MainThread是挂起状态,代码不会继续向下运行,需要加joinable的地方应该是我们预计这个WorkThread即将完成任务时或者MainThread要结束的时候添加。一是保证MainThread不会在应该运行时挂起,二是保证WorkThread能够正常退出。
与joinable相关的还有个join方法,实际上join方法才是真正的等

使用Lmabda表达式(匿名函数)来为工作线程传入参数

Lmabda表达式是一种匿名函数,很适合某个方法只运行一次或者操作一次时使用,这样我们不必再额外添加一个方法或者在已经封装好的类中添加成员方法,这都不符合封装开放原则。Lmabda表达式就很合适解决这类问题。
Lmabda表达式的结构如下:

//Lmabda Function as same as inline Function
	//lambda Function def No name,It is useful to Quickly code a algorithm
	//auto RealWorks = [&counter2, &TotalValue_2](auto IterStart, auto IterEnd) {
	//	for (; IterStart != IterEnd; ++IterStart) {
	//		TotalValue_2 += Count_Up(*IterStart);
	//		counter2.Add_Value();
	//	}
	//};
auto localvalue = [函数对象参数](操作符重载函数参数)mutable 或 exception 声明 -> 返回值类型{函数体};

[函数对象参数]

标识Lmabda表达式的开始,这部分是基础,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义 Lambda 为止时 Lambda 所在作用范围内可见的局部变量(包括 Lambda 所在类的 this)。
也就是说如果要在Lmabda表达式中使用局部变量的时候,需要在[]中将其显式的写出,这样编译器才会去寻找这些局部变量,并将其加载到Lmabda表达式中。
下面给出函数对象参数的形式:

  1. [] 不传入任何对象参数

  2. [=] 函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)

  3. [&] 函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是引用传递方式(相当于是编译器自动为我们按引用传递了所有局部变量)。

  4. [this] 函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是引用传递方式(相当于是编译器自动为我们按引用传递了所有局部变量)。

  5. [Value] 将 Value 按值进行传递。按值进行传递时,函数体内不能修改传递进来的 a 的拷贝,因为默认情况下函数是 const 的,要修改传递进来的拷贝,可以添加 mutable 修饰符。

  6. [&Value] 将 Value 按引用进行传递。

  7. [A,&B] 将A按值传递,B按引用进行传递。

  8. [=,&A,&B] 除A和B按引用进行传递外,其他参数都按值进行传递。

  9. [&,A,B] 除A和B按值进行传递外,其他参数都按引用进行传递。.

(操作符重载函数参数)

标识重载的 () 操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如: (a, b))和按引用 (如: (&a, &b)) 两种方式进行传递。

mutable 或 exception 声明

这部分可以省略。按值传递函数对象参数时,加上 mutable 修饰符后,可以修改传递进来的拷贝(注意是能修改拷贝,而不是值本身)。exception 声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw(int)。

-> 返回值类型

标识函数返回值的类型,当返回值为 void,或者函数体中只有一处 return 的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。

{函数体}

标识函数的实现,这部分不能省略,但函数体可以为空。

例子

void ShowIt(int X, int Y, int Z) { 
	std::cout << X << " " << Y << " " << Z << " " << std::endl; 
}
void Plus(int X, int Y, int& Z) { Z += X + Y; }
void PrintString(const std::string& str1, const std::string& str2) {
	std::cout << "Hello " << str1 << " " << str2 << std::endl;
}

void TestPart4(){
	int X = 2;
	int Y = 2;
	int Z = 3;
	std::thread th1([=](){ShowIt(X, Y, Z); });
	th1.join();
	std::thread th2(ShowIt, X, Y, Z);//only in the Value Pass way;
	//std::thread th2(Plus, X, Y, Z)//error!
	th2.join();
	std::thread th3([=, &Z]() {Plus(X, Y, Z); });
	th3.join();
	std::thread th4(Plus,X,Y,std::ref(Z));//ref is a class
	th4.join();

	std::string str1("ABC");
	std::string str2("DEF");
	std::thread th5([&](){PrintString(str1, str2); });
	th5.join();
	std::thread th6(PrintString,str1,str2);
	th6.join();
	std::thread th7(PrintString, std::cref(str1), std::cref(str2));
	th7.join();
}

多线程的同步问题初探

多线程比起单线程有着速度和效率上的优势,但是如果多个线程共享同一份数据,并进行操作,结果是不可预见的,同步就是多线程编程的一大难点,最经典的银行取钱问题,要保证每一步都是原子操作,并且有些本来是两步以上的动作也应该组合到一步完成,这里我们需要用到<atomic>头文件,保证每一步都是原子操作,结合Mutex来将多个步骤组合成一个原子操作。

//include <atomic> //Change the "int" to be a atomic
//at the Multithread coding,if we should't share the data in workthread,
//then we need to cut down the data in different thread.


//Change the "int" to be a atomic

template<typename Type>
class Counter
{
public:
	Type Get_Type_Value()const { return Sum; }
	void Add_Value() { Sum++; }
	void Add_Resource(Type Value) { TotalResource++; }
	int AveResource() {
		if (Sum == 0)return 1;
		return TotalResource / Sum;
	}
	Counter() :Sum{ Type() },TotalResource {Type()}{}
private:
	std::atomic<Type> Sum;//Change the "int" to be a atomic
	std::atomic<Type> TotalResource;//but atomic can't make the two sentences like a atomic
};

template<typename Type>
Type Count_Up(Type Value)
{
	//count up the value
	return Value + Value;
}

template<typename Iter>
void RealWorks(Counter<int>& counter2, int64_t& TotalValue_2, Iter IterStart, Iter IterEnd) {
	for (; IterStart != IterEnd; ++IterStart) {
		TotalValue_2 += Count_Up(*IterStart);
		counter2.Add_Value();
		counter2.Add_Resource(1);
	}
};

bool Testthread(Counter<int>& counter, int Max_Count) {
	auto count = counter.Get_Type_Value();
	auto Ave = counter.AveResource();
	if (Ave != 1) { std::cout << "There are something error happed\n"; };
	if (count == Max_Count)return true;
	else return false;
}

int main()
{
	//TestPart4();
	std::vector<int> Box;
	//Attention:some times,MultiThread maybe count up wrong but Single Thread would count up right.
	//Example:
	for (unsigned int i = 0; i < 10000000; i++) { Box.push_back(rand() % 100); }
	Counter<int> counter;
	int Size = Box.size();
	auto Iter = Box.begin() + (Size / 3);
	auto Iter_Mid = Box.begin() + (Size / 3 * 2);
	auto Iter_End = Box.end();
	int64_t TotalValue_2 = int64_t();
	std::thread th1([=, &counter,&TotalValue_2] {RealWorks(counter, TotalValue_2, Iter, Iter_Mid); });
	std::thread printThread([&counter, &TotalValue_2] {
		while (!Testthread(counter, 10000000));
		});
	std::thread th2([=, &counter, &TotalValue_2] {RealWorks(counter, TotalValue_2, Iter_Mid,Iter_End); });
	RealWorks(counter, TotalValue_2, Box.begin(), Iter);
	th1.join();
	th2.join();
	printThread.join();//dead loop
	return 0;
}

例子中使用了printThread这个线程来检测是否数据自加正确,发现如果不使用atomic一定是不正确的,因为++操作本身不是一个原子操作,给int设置为atomic类型。std::atomic<int> Sum;这样在使用int类型的Sum时,相当于在调用一个函数。关于Mutex的相关内容,在Part.3介绍。

c++学习 part2 多线程 多线程 阅读详情

相关推荐

C++ Concurrency in Action, 2nd Edition C++ 并发编程实战 第二版 note part 1

复制数据返回给调用者可能会抛出异常,被pop出来的值只有在栈完成修改以后才会返回给调用者,所以栈首先删除了这个值,然后这个值才被复制并返回。此时复制时抛出异常,就导致了刚刚pop掉的值丢失了,而且已经被栈删除了。std::stack操作的设计者将这个操作分成了两个:获取栈顶的值top,从栈内删除这个值pop。若你不能安全的复制这个值,那么它还在栈内。当然若只是缺少堆内存,释放内存就可以了。从上面的讲述可以发现:某些组合起来的操作,需要分开才行。

邹九的个人博客 1951

lambda表达式之求和,分组排序,for循环

1.求和 List<AjStatResponse> result = new ArrayList<>(); Integer sum = result.stream().mapToInt(AjStatResponse::getJcajsl).sum(); 似乎都是用流的方式获取,这里stream()可以求double long short 等基本类型的合,当然,sum(...

Qii_yuan的博客 6988

VScode配置C++开发环境 part1

VScode是一款跨平台轻量级的代码编辑器,也是我目前最爱用的啦!以前都是用它写python,现在要学习C++,今天就记录一下在VScode里面配置C++开发环境的过程(win10 64位系统)。 准备工作 安装MinGW。推荐安装MinGW64,因为它支持C++11多线程编程。(PS: 我最开始安装的MinGW32,但是在编译多线程代码的时候一直有问题,最后换成了MinGW64) MinGW安装...

peach_blossom的博客 1183

【C++】C++ 11Lambda表达式(学习笔记)

01、文章目录 文章目录01、文章目录02、Lambda表达式03、函数式编程04、Lambda Syntax05、Lambda的使用场景06、Lambda示例6.1 示例一6.2 示例二07、小结 02、Lambda表达式 lamda表达式是c++11规范引入的新语法。“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。 lamb

Cain Xcy的博客 654

Claude Code平替实测:TRAE能否取代?深度对比与选型指南

随着AI编程助手从补全工具演进为能自主执行任务的代码智能体,开发者需要在效果与成本之间做出权衡。智能代理通过读文件、改代码、跑命令的闭环循环,显著提升开发效率,但不同工具在上下文管理、任务理解深度和计费模式上差异显著。其中,Claude Code以其强大的语义理解和长任务稳定性著称,而TRAE则以免费积分、低门槛和国内直连吸引大量用户。本文基于真实项目实测,从安装配置、日常开发、复杂重构、成本核算等维度对比两者,并拆解MCP、Skills等易踩坑的配置细节,帮助开发者根据不同场景选择合适工具,实现效率与预算

weixin_34007020的博客 255

基于Open Cluster Management构建企业级多Kubernetes集群管理平台OpenClaw

在云原生架构中,Kubernetes已成为容器编排的事实标准。随着业务规模扩大,企业往往需要管理分布在多个云环境或数据中心的Kubernetes集群,这带来了集群管理、应用分发、策略统一和监控运维等复杂挑战。多集群管理技术通过提供统一控制平面,实现了对分布式资源的集中管控,其核心价值在于提升运维效率、保障安全合规并降低管理成本。Open Cluster Management(OCM)作为CNCF沙箱项目,采用Kubernetes原生架构,通过自定义资源定义(CRD)和控制器模式,为构建多集群管理平台提供了标

weixin_33747129的博客 368

C++Lambda表达式,超详细的讲解,保证一遍懂

https://blog.csdn.net/u014711890/article/details/123441799

lyshiba的专栏 4742

Python+Tableau 全流程数据分析实战:从数据清洗到商业洞察可视化

本文通过Python+Tableau完整演示电商销售数据分析流程。首先使用Python进行数据清洗(缺失值处理、异常值过滤等)和探索性分析(商品类别、时间趋势等),然后导入Tableau创建交互式可视化仪表盘。分析发现电子产品销售额最高但利润率低,美妆类利润率最优,东部地区销售表现最好。最终提出优化供应链、加强美妆推广等商业建议,展示了Python数据处理与Tableau可视化的高效配合。所有代码可直接运行,适合数据分析初学者和从业者实战参考。

weixin_44520581的博客 337

C++中的lambda表达式及底层实现原理

什么是lamber表达式 表达式格式 [ 捕捉列表 ](参数列表)mutable -> 返回值 { 函数体 }; 捕捉列表:处于lamber函数开始位置,编译器根据[]来判断接下来的代码是否为lamber表达式 ...

YIUECHEN的博客 5090

Token算力工厂建设方案:从GPU集群到计量计费的全链路设计

在AI应用从“租核”走向“买Token”的范式转换中,算力交付的核心指标已不再是vCPU或GPU实例,而是单位时间内的Token产出量与单Token成本。这一变化推动基础设施从资源租赁向计件生产演进,要求GPU集群、推理引擎、调度系统、计量计费等模块像工厂产线一样协同运转。本文从硬件异构混部、存储网络设计、推理引擎调优、Token网关与配额管理、稳定性治理等维度,系统拆解如何构建一座可量化、可计费、可扩展的Token算力工厂,并给出分三期落地的推进节奏,帮助架构师与技术管理者在AI基础设施建设中实现成本可控

weixin_29095587的博客 265

泛型lambda表达式

对泛型lambda表达式及应用进行分析说明

fpcc的专栏 1002

使用MATLAB实时处理摄像头图像

本文介绍了如何使用MATLAB进行实时图像处理,包括从摄像头获取图像、对图像进行处理并显示处理结果。我们将演示如何使用MATLAB的图像处理工具箱来实现常见的图像处理任务,如图像增强、边缘检测和物体检测。

XsiJava的博客 921

C++11 并发编程教程 - Part 1 : thread 初探

C++11 引入了一个新的线程库,包含了用于启动、管理线程的诸多工具,与此同时,该库还提供了包括互斥量、锁、原子量等在内的同步机制。在这个系列的教程中,我将尝试向大家展示这个新库提供的大部分特性。 为了能够编译本文的示例代码,你需要有一个支持 C++11 的编译器,笔者使用的是 GCC4.6.1(你需要添加 "-std=c++11" 或 "-std=c++0x" 编译选项以启动 GCC 对

u012432785的博客 427

【Bug已解决】codex: tool call timeout / Function execution exceeds limit — CodeX CLI 工具调用超时解决方案

CodeX CLI 工具调用超时(Bash/文件/MCP)的解决方案,含增加超时、拆分命令、后台运行、避免交互卡住与限制读取。

博客 4205

Vue - 简约大气 404 页面

效果图 实现代码 复制即可。 <template> <div> <div class="error"> <!-- 图片可保存到本地 --> <img src="https://img-blog.csdnimg.cn/20210715111039922.png"> <p>抱歉!你访问的页面不存在或已删除 :( </p> <span class="back" @click="go(

🏆 前端领域优质创作者 3371

C++11 并发教程——Part2:保护共享数据

在前面一篇文章,我们知道怎么使用线程并行地执行程序。在每个线程中执行的代码都是独立的。通常情况下,多个线程之间会用到共享数据。此时,我们就会面临一个问题:同步。 通过下面一段简单的代码来分析同步问题。 同步问题 下面这个例子,我们探讨一个简单的计数器类。这个类有一个数据成员value和成员函数(增加数据成员value)。 class Counter { public: voi

wangyangkobe的专栏 1810

Python 爬虫教程:金融数据定向抓取(银行 + 投资网站数据结构化提取)

在当今数字化时代,金融数据的获取和分析对于投资者、分析师以及金融机构来说至关重要。Python 爬虫技术可以帮助我们高效地从各种网站上抓取金融数据,从而为投资决策、风险评估和市场分析提供支持。本文将详细介绍如何使用 Python 爬虫技术来定向抓取银行和投资网站的数据,并将其结构化提取,以便进一步分析和使用。

u014481728的博客 881

std string与线程安全_C++标准库多线程简介Part1

Part1:线程与互斥量本篇文章将简单的介绍一下C++的标准线程库,本篇内容十分基础,如果你有C++多线程相关的使用经验或者知识,就不必在这篇文章上浪费时间了...如果你认为本篇文章对你有帮助,请点赞!!!1.进程与线程在介绍标准库多线程之前,需要先介绍一下进程与线程的概念与它们之间的差别。进程是被执行的应用程序(程序即指令(code)与数据(data)的集合)的实例(可以启动多个相同的应用程序,...

weixin_33180221的博客 936

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Studying-多线程学习Part3 - condition_variable与其使用场景、C++11实现跨平台线程池

condition_variable与其使用场景、C++11实现跨平台线程池

yachihaoteng的博客 834

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

C++11多线程编程 第七章: 条件变量及其使用方法

C++11 Multithreading – Part 7: Condition Variables Explained Varun June 2, 2015 C++11 Multithreading – Part 7: Condition Variables Explained2018-08-18T15:21:29+00:00C++, C++ 11, c++11 Threads, Multit...

along 591

C++11 并发编程教程 - Part 2 : 保护共享数据

C++11 并发编程教程 - Part 2 : 保护共享数据C++11 并发编程教程 - Part 2 : 保护共享数据注:文中凡遇通用的术语及行话,均不予以翻译。译文有不当之处还望悉心指正。原文:C++11 Concurrency - Part 2 : Protect shared data   上一篇文章我们讲到如何启动一些线程去并发地执行某些操作,虽然那些在线程里执行的代码都是独立的,但通常...

杨氏计算机知识整理 147

C++11 std::thread 多线程编程:从基础原理到实战优化

并发编程是现代软件开发的核心概念,它允许程序同时执行多个任务,从而充分利用多核CPU的计算能力,提升系统吞吐量和响应速度。其基本原理是通过操作系统提供的线程机制,创建多个独立的执行流。在C++中,std::thread作为C++11标准库引入的线程管理类,提供了统一、可移植的线程抽象,其价值在于终结了平台相关API的混乱,极大地提升了代码的可移植性。std::thread的设计深刻体现了资源所有权和移动语义,强制开发者明确线程生命周期,以避免资源泄漏。在实际应用场景中,如高性能计算、游戏引擎或服务器开发,s

weixin_30905981的博客 329

c++面试常见题·Part 1 基础

new&delete、malloc&free 都能动态申请内存和释放内存 malloc&free是标准库函数,new&delete是运算符,对于非内部数据类型的对象而言,只有new,delete能自动调用对象的构造函数和析构函数 指针和引用 指针指向变量的地址,引用是变量的别名, 引用不占内存单元,指针本身占4字节 引用必须初始化,并在初始化后不能修改,而指...

cytheria43的博客 269

C++多线程断点续传下载器:从原理到实战代码实现

多线程编程是提升程序并发性能的核心技术,其原理在于通过创建多个执行流并行处理任务,充分利用多核CPU的计算能力。在文件下载等I/O密集型场景中,多线程技术能显著减少网络等待时间,提升吞吐量。结合HTTP协议的Range请求头,可以实现文件的分块下载,这是断点续传功能的技术基础。将多线程与断点续传结合,能够构建出高效、可靠的下载工具,广泛应用于各类客户端软件和分布式系统中。本文以C++后端开发为背景,通过一个完整的实战案例,详细解析了如何设计一个支持多线程并发下载与断点续传的文件下载器,涵盖了线程同步、进度持

virusswb的专栏 418
上一篇: undered_map Part.1
烧幽香的花
博客等级 码龄14年 13粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值