9.0-chinese
发表于|更新于|C++
|总字数:290|阅读时长:1分钟|浏览量:
第9章 高级线程管理
本章主要内容
- 线程池
- 处理线程池中任务的依赖关系
- 池中线程如何获取任务
- 中断线程
之前的章节中,我们通过创建std::thread对象来对线程进行管理。在一些情况下,这种方式不可行了,因为需要在线程的整个生命周期中对其进行管理,并根据硬件来确定线程数量,等等。理想情况是将代码划分为最小块,再并发执行,之后交给处理器和标准库,进行性能优化。
另一种情况是,当使用多线程来解决某个问题时,在某个条件达成的时候,可以提前结束。可能是因为结果已经确定,或者因为产生错误,亦或是用户执行终止操作。无论是哪种原因,线程都需要发送“请停止”请求,放弃任务,清理,然后尽快停止。
本章,我们将了解一下管理线程和任务的机制,从自动管理线程数量和自动管理任务划分开始。
文章作者: Estom
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Estom的博客!
相关推荐

2022-12-05
04.详解 ThreadPoolExecutor 的参数含义及源码执行流程?
详解 ThreadPoolExecutor 的参数含义及源码执行流程?线程池是为了避免线程频繁的创建和销毁带来的性能消耗,而建立的一种池化技术,它是把已创建的线程放入“池”中,当有任务来临时就可以重用已有的线程,无需等待创建的过程,这样就可以有效提高程序的响应速度。但如果要说线程池的话一定离不开**ThreadPoolExecutor,在阿里巴巴的《Java开发手册》中是这样规定线程池的:线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor**的方式,这样的处理方式让写的读者更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors 返回的线程池对象的弊端如下: 1)FixedThreadPool 和 SingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM(Out Of Memory) 2)CachedThreadPool 和 ScheduledThreadPool:允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 ...

2021-09-07
3.1-chinese
3.1 共享数据带来的问题当涉及到共享数据时,问题很可能是因为共享数据修改所导致。如果共享数据是只读的,那么只读操作不会影响到数据,更不会涉及对数据的修改,所以所有线程都会获得同样的数据。但是,当一个或多个线程要修改共享数据时,就会产生很多麻烦。这种情况下,就必须小心谨慎,才能确保一切所有线程都工作正常。 不变量(invariants)的概念对程序员们编写的程序会有一定的帮助——对于特殊结构体的描述;比如,“变量包含列表中的项数”。不变量通常会在一次更新中被破坏,特别是比较复杂的数据结构,或者一次更新就要改动很大的数据结构。 双链表中每个节点都有一个指针指向列表中下一个节点,还有一个指针指向前一个节点。其中不变量就是节点A中指向“下一个”节点B的指针,还有前向指针。为了从列表中删除一个节点,其两边节点的指针都需要更新。当其中一边更新完成时,不变量就被破坏了,直到另一边也完成更新;在两边都完成更新后,不变量就又稳定了。 从一个列表中删除一个节点的步骤如下(如图3.1) 找到要删除的节点N 更新前一个节点指向N的指针,让这个指针指向N的下一个节点 更新后一个节点指向N的指针,让这个...

2021-03-30
2.5 进程与线程
1 进程与线程进程 进程是资源分配的基本单位。进程控制块 (Process Control Block, PCB) 描述进程的基本信息和运行状态,所谓的创建进程和撤销进程,都是指对 PCB 的操作。 下图显示了 4 个程序创建了 4 个进程,这 4 个进程可以并发地执行。 线程 线程是独立调度的基本单位。一个进程中可以有多个线程,它们共享进程资源。 线程栈是在进程的堆中分配栈空间,每个线程拥有独立的栈空间,为了避免线程之间的栈空间踩踏,线程栈之间还会有以小块guardsize用来隔离保护各自的栈空间,一旦另一个线程踏入到这个隔离区,就会引发段错误。 QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。 区别 调度。线程是独立调度的基本单位,进程是资源分配的基本单位。在同一进程中,线程的切换不会引起进程切换,从一个进程中的线程切换到另一个进程中的线程时,会引起进程切换。 并发性。线程使得操作系统具有更好的并发性,从...

2021-09-07
7.3-chinese
7.3 对于设计无锁数据结构的指导建议本章中的例子中,看到了一些复杂的代码可让无锁结构工作正常。如果要设计自己的数据结构,一些指导建议可以帮助你找到设计重点。第6章中关于并发通用指导建议还适用,不过这里需要更多的建议。我从例子中抽取了几个实用的指导建议,在你设计无锁结构数据的时候就可以直接引用。 7.3.1 指导建议:使用std::memory_order_seq_cst的原型std::memory_order_seq_cst比起其他内存序要简单的多,因为所有操作都将其作为总序。本章的所有例子,都是从std::memory_order_seq_cst开始,只有当基本操作正常工作的时候,才放宽内存序的选择。在这种情况下,使用其他内存序就是进行优化(早起可以不用这样做)。通常,当你看整套代码对数据结构的操作后,才能决定是否要放宽该操作的内存序选择。所以,尝试放宽选择,可能会让你轻松一些。在测试后的时候,工作的代码可能会很复杂(不过,不能完全保证内存序正确)。除非你有一个算法检查器,可以系统的测试,线程能看到的所有可能性组合,这样就能保证指定内存序的正确性(这样的测试的确存在),仅是执...

2021-09-02
sync
概述sync包对并发和同步机制进行了实现,但显然并发编程这样一个话题过于庞大,无法在一篇博客里面详细展开,所以本文的重点放在sync包的使用。 不过这里首先对并发的背景进行简单的介绍,在单线程的程序中,同一个时刻只存在一个线程对数据进行访问,访问永远是线性的,不需要额外的机制保障;但是当同时存在多个线程可能同时访问一个数据时,由于线程调度的特性,会带来难以预料的结果。试想如下代码会输出什么结果,正常情况会是3,但实际上可能的结果是2或者3,这是由于函数或者代码的运行没有原子性,比如在线程1执行Add1操作时被暂停了(已经读取data,还未写回),然后开始运行线程2,并读取数据,然后两个线程依次执行到结束,由于两个线程读取的值都是data=1,执行Add1后都得到2,而非3。 123456789101112131415161718import ( "fmt" "time")func Add1(data *int) { tmp = *data *data = tmp + 1}fu...

2021-09-07
8.2-chinese
8.2 影响并发代码性能的因素`多处理系统中,使用并发的方式来提高代码的效率时,你需要了解一下有哪些因素会影响并发的效率。即使已经使用多线程对关注进行分离,还需要确定是否会对性能造成负面影响。因为,在16核机器上应用的速度与单核机器相当时,用户是不会打死你的。 之后你会看到,在多线程代码中有很多因素会影响性能——对线程处理的数据做一些简单的改动(其他不变),都可能对性能产生戏剧性的效果。所以,多言无益,让我们来看一下这些因素吧,从明显的开始:目标系统有多少个处理器? 8.2.1 有多少个处理器?处理器个数是影响多线程应用的首要因素。在某些情况下,你对目标硬件会很熟悉,并且针对硬件进行设计,并在目标系统或副本上进行测量。如果是这样,那你很幸运;不过,要知道这些都是很奢侈的。你可能在一个类似的平台上进行开发,不过你所使用的平台与目标平台的差异很大。例如,你可能会在一个双芯或四芯的系统上做开发,不过你的用户系统可能就只有一个处理器(可能有很多芯),或多个单芯处理器,亦或是多核多芯的处理器。在不同的平台上,并发程序的行为和性能特点就可能完全不同,所以你需要仔细考虑那些地方会被影响...
公告
欢迎参观Estom的小屋




