《线程管理:传递参数、确定线程数量、线程标识》

参考《c++ Concurrency In Action 》第二章做的笔记

目录

  • 传递参数
  • 量产线程
  • 线程标识

传递参数

thread构造函数的附加参数会拷贝至新线程的内存空间中,即使函数中的采纳数是引用类型,拷贝操作也会执行。如果我们期待传入一个引用,必须使用std::ref将参数转换成引用形式:

如下:

void update_weight(weight_id w,weight_data& data);	//1
void oops(weight_id w)
{weight_data data;//错误方式std::thread t(update_weight,w,data);//正确方式std::thread t(update_weight,w,std::ref(data));display_status();t.join();
}

这样就能收到data的引用,而非data的拷贝副本。

std:bind的传参机制相同,使用std::thread创建线程时,传递参数的过程如下:

  • std::thread构造函数传参:一般实参会被拷贝至新线程的内存空间。具体拷贝的过程是由调用线程(主线程)在堆上创建并交由子线程管理,在子线程结束时同时被释放。
  • 向线程函数传参:由于std::thread对象里一般保存的是参数的副本,为了效率同时兼顾一些只移动类型的对象,所有的副本均被std::move到线程函数,即以右值的形式传入。

示例:std::move转移动态对象的所有权到线程中去:

void process_big_object(std::unique_ptr<big_object>);std::unique_ptr<big_object> p(new big_object);
p->prepare_data(47);
std::thread t(process_big_object,std::move(p));

在thread构造函数中执行move,big_object对象的所有权首先转移到新创建线程的内部存储中,之后再传递给process_big_object函数。

量产线程

void do_work(unsigned id);void f()
{std::vector<std::thread> threads;for(unsigned i = 0; i < 20; i++)threads.emplace_back(do_work,i);	//产生线程for(auto& entry : threads)				//对每个线程调用join()entry.join();
}

使用线程去分割一个算法的工作总量,所以在算法结束之前,所有线程必须结束。线程所做的工作都是独立的,并且结果仅会受到共享数据的影响。如果f有返回值,在写入返回值之前,程序会检查使用共享数据的线程是否终止。

下面函数,会返回并发线程的数量

std::thread::hardware_concurrency()

下面展示并行版本的std::accumulate。代码将整体工作拆分成小任务,交给每个线程去做,并设置最小任务数,避免产生太多的线程,程序会在操作数量为0时抛出异常。

template<typename Iterator,typename T>
struct accumulate_block
{void operator()(Iterator first,Iterator last,T& result){result = std::accumulate(first,last,result);}
};template<typename Iterator,typename T>
T parallel_accumulate(Iterator first,Iterator last,T init)
{unsigned long const length = std::distance(first,last);if(!length)		//1return init;unsigned long const min_per_thread = 25;unsigned long const max_threads = (length+min_per_thread-1)/min_per_thread;		//2unsigned long const hardware_threads = std::thread::hardware_concurrency();unsigned long const num_threads = 								//3std::min(hardware_threads != 0 ? hardware_threads : 2,max_threads);unsigned long const block_size = length / num_threads;			//4std::vector<T> results(num_threads);std::vector<std::thread> threads(num_threads - 1);				//5Iterator block_start = first;for(unsigned long i = 0; i < num_threads-1; ++i){Iterator block_end = block_start;std::advance(block_end,block_size);							//6threads[i] = std::thread(									//7accumulate_block<Iterator,T>(),block_start,block_end,std::ref(result[i]));block_start = block_end;									//8}accumulate_block<Iterator,T>(),block_start,last,results[num_threads-1]);				//9for(auto& entry : threads)entry.join();												//10return std::accumulate(results.begin(),results.end(),init);		//11		
}

函数解释:

如果输入范围为空1,就会得到init值。如果范围内的元素多于1个,需要用范围内元素的总数量除以线程块中最小任务数,从而确定启动线程的最大数量。由于上下文切换可能会降低线程性能,所以计算最大线程数以及硬件支持线程数,选择较小值作为启动线程数量3。如果为0的话,选择2替代。

每个线程中处理的元素数量,是范围中元素的总量除以线程的个数得出的4。

既然确定了线程个数,创建一个std::vector<T>容器存放中间结果,并为线程创建一个std::vector<std::thread>容器。因为在启动之前已经有了一个主线程,所以启动线程数是num_threads-1。

使用循环启动线程,block_end指向当前块的末尾6,并启动一个新线程为当前块累加结果7.当迭代器指向当前块的末尾时,启动下一个块8.

启动所有县城后,9中线程会处理最终块的结果,累加最终块结果后,等待std::for_each创建线程10.之后使用std::accumulate将所有结果进行累加11

线程标识

线程标识为std::thread::id类型,可以通过成员函数get_id()来获取。如果thread对象没有和任何执行线程相关联,将返回一个默认构造值,表示“无线程”。

如果两个线程id相等,说明是同一个线程,或者都是“无线程”。

std::thread::id实例常用作检测线程是否需要进行一些操作,比如,当用线程来分割一项工作,主线程可能要做一些与其他线程不同的工作,启动其他线程前,可以通过get_id得到自己线程id,每个线程都检查一下,其拥有线程id是否与初始线程id相同。

std::thread::id master_thread;
void some_core_part_of_algorithm()
{if(std::this_thread::get_id() == master_thread)do_master_thread_work();elsedo_common_work();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/377038.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手把手玩转win8开发系列课程(14)

这节的议程就是——添加appbar appbar是出现在哪儿了&#xff0c;出现在屏幕的底部。他能使用户能用手势或者使用鼠标操作程序。metro UI 重点是在主要的控件使用许多控件&#xff0c;使其用户使用win8电脑更加的方便。而appBar使其用户体验更好。在这节中&#xff0c;我将告诉…

No identities are available for signing 的解决办法

今天重新上传做好的app提交到app store&#xff0c;结果就出现标题上的错误。“No identities are available for signing”。 以后碰到这样的问题按照下面几个步骤来做&#xff1a; 进入Distribution -----下载发布证书 -----双击安装-----重启Xcode就能上传了 其他细节 如果再…

半连接反连接

半连接&反连接 1. 半连接 半连接返回左表中与右表至少匹配一次的数据行&#xff0c;通常体现为 EXISTS 或者 IN 子查询。左表驱动右表。只返回左表的数据&#xff0c;右表作为筛选条件。 可以用 EXISTS、 IN 或者 ANY 举例&#xff1a;表t1和表t2做半连接&#xff0c;t…

匿名方法和Lambda表达式

出于MVVM学习的需要&#xff0c;复习下匿名方法和Lambda表达式&#xff0c;因为之前用的也比较少&#xff0c;所以用的也不是很熟练&#xff0c;Baidu下相关的知识&#xff0c;写了这个Demo&#xff0c;目标是用简单的方法展示这个怎么用。 这里偏重的和LINQ中的Lambda表达式 …

烂橘子

Problem Statement: 问题陈述&#xff1a; Given a matrix of dimension r*c where each cell in the matrix can have values 0, 1 or 2 which has the following meaning: 给定尺寸r * C的矩阵&#xff0c;其中矩阵中的每个单元可以具有其具有以下含义的值0&#xff0c;1或2…

android junit 测试程序

http://blog.csdn.net/to_cm/article/details/5704783 Assert.assertEquals(2, t); 断言转载于:https://www.cnblogs.com/wjw334/p/3714120.html

MySQL 8.0.22执行器源码分析HashJoin —— BuildHashTable函数细节步骤

BuildHashTable函数细节步骤 该函数位置处于hash_join_iterator.cc 403 ~ 560行 step1&#xff1a;如果被驱动表迭代器没有更多的行数&#xff0c;更新m_state为EOR&#xff0c;然后返回false&#xff0c;表明创建hash表失败 if (!m_build_iterator_has_more_rows) {m_state…

《那些年啊,那些事——一个程序员的奋斗史》——125

距离离职交接的一个月时间还剩几天&#xff0c;本来应该是平淡无事的&#xff0c;却没想到最后还是波澜四起。昨天下班前&#xff0c;公司突然停了电。这本是件普通得不能再普通的事情&#xff0c;可没想到过了一会来电了&#xff0c;或许是波峰电压太大&#xff0c;或许是稳压…

python中的元类_Python中的元类

python中的元类Python元类 (Python metaclass) A metaclass is the class of a class. A class defines how an instance of a class i.e.; an object behaves whilst a metaclass defines how a class behaves. A class is an instance of a metaclass. 元类是类的类。 一个类…

MySQL 8.0.22执行器源码分析HashJoin —— 一些初始化函数的细节步骤

目录InitRowBuffer&#xff08;101行~126行&#xff09;InitProbeIterator&#xff08;142行~153行&#xff09;*HashJoinIterator* 的Init&#xff08;155行~240行&#xff09;InitializeChunkFiles&#xff08;364行~401行&#xff09;InitWritingToProbeRowSavingFile&#…

c语言的宏定义学习笔记

宏定义 在预处理之前&#xff0c;c预处理器会对代码进行翻译&#xff0c;譬如用blank替换注释&#xff0c;去掉多余的空格&#xff0c;删除末尾的\来拼接行等。 例如&#xff1a; int /*注释*/ x; 会被翻译成 int x; printf("this is a s\ entence."); 会被翻译成 pr…

摄氏温度转换华氏温度_什么是摄氏温度?

摄氏温度转换华氏温度摄氏温度 (Celsius) Celsius is a temperature measuring scale which as a SI unit derived from the seven base units stated and described by the International System of Units (SI). 摄氏温度是一种温度测量刻度&#xff0c;它是由国际单位制(SI)所…

别人的算法学习之路

http://www.cnblogs.com/figure9/p/3708351.html 我的算法学习之路 关于 严格来说&#xff0c;本文题目应该是我的数据结构和算法学习之路&#xff0c;但这个写法实在太绕口——况且CS中的算法往往暗指数据结构和算法&#xff08;例如算法导论指的实际上是数据结构和算法导论&a…

git config命令使用第二篇——section操作,多个key值操作,使用正则

接上一篇&#xff0c;git config命令使用第一篇——介绍&#xff0c;基本操作&#xff0c;增删改查:http://blog.csdn.net/hutaoer06051/article/details/8275069 1. 删除一个section 命令参数 --remove-section 格式&#xff1a;git config [--local|--global|--system] --rem…

MySQL面试准备——64页pdf

本笔记为以前整理的零碎的关于Mysql的知识点&#xff0c;有深入源码的也有浅层的八股。已经被我整理成了一个pdf。 实习岗位正好也是和数据库内核有关的&#xff0c;之后应该还会更新。做个整理&#xff0c;方便秋招的时候快速回顾吧。 链接&#xff1a;链接 提取码&#xff1a…

python点图_Python | 点图

python点图The dot plot is a type of data representation in which each data-point in the figure is represented as a dot. Dot plot underlies discrete functions unlike a continuous function in a line plot. Each value could be correlated but cannot be connecte…

SAP-MM:发票、贷方凭证、事后借记、后续贷记

发票和事后借记 相同点&#xff1a;增加对供应商的应付款 不同点&#xff1a;针对同一订单收货&#xff0c;发票要先于事后借记&#xff08;事后借记是对供应商后期发票金额的补充&#xff09;&#xff1b;发票和金额、订单数量有关系&#xff0c;而事后借记只是订单金额调整的…

Dijkstra for MapReduce (1)

<math xmlns"http://www.w3.org/1998/Math/MathML"><mi>x</mi><mo>,</mo><mi>y</mi><mo>&#x2208;<!-- ∈ --></mo><mi>X</mi> </math> 准备研究一下Dijkstra最短路径算法Hadoop上…

sql的外键约束和主键约束_SQL约束

sql的外键约束和主键约束SQL | 约束条件 (SQL | Constraints) Constraints are the guidelines implemented on the information sections of a table. These are utilized to restrict the kind of information that can go into a table. This guarantees the precision and …

nios pio interrupt 的使能

关于nios 中的中断&#xff0c;因为要16c550中需要nios的中断环境去测试&#xff0c;所以就用到了中断。 硬件&#xff1a;在nios中添加硬件PIO,但是要使能中断功能。如下图所示&#xff1a; 系统列化&#xff0c;PIO的连接就不说了。但是要注意两地方&#xff1a;edge type&am…