Go学习笔记—多线程

多线程编程

​ 一个进程可以包含多个线程,这些线程运行的一定是同一个程序(进程==程序),且都由当前进程中已经存在的线程通过系统调用的方式创建出来。进程是资源分配的基本单位,线程是调度运行的基本单位,线程不可独立于进程存在。

​ 所有线程都有自己的线程栈,以此存放自己的私有数据(包含在进程的虚拟内存地址中)。一个进程中的很多资源也会被线程所共享,包括在当前进程虚拟内存地址中存放的代码段、数据段、堆、信号处理函数、文件描述符(非负整数)。正因如此,创建一个线程时不会像创建一个进程时那样耗费资源,因为其大多数资源都因共享而无需被复制。

(一)线程简介

一、线程状态

​ 与进程这种家族式的树状结构不同,线程之间的关系都是平等的。他们可以互相进行如下四种操作。

操作作用
pthread_create创建线程——除主线程随着进程一同创建,其他线程都通过线程传入代码段与参数来创建,并会返回TID。
pthread_cancel(TID)终止线程——取消给定TID代表的线程,目标线程总是会接受该请求并在某取消点响应该请求。
pthread_join(TID)连接已终止线程——一直等待到该TID代表的线程终止,并将其返回值告知调用线程。
pthread_detach(TID)分离线程——将目标线程变为不可被连接。内核会在其终止时自动进行清理和销毁工作。

在这里插入图片描述

注意:

(1)线程默认都是一个可连接线程。如果在其终止时未被连接,则会变成一个僵尸线程,当有其他进程连接该僵尸进程,则会被回收。

(2)分离操作是不可逆的操作。

(3)创建新城需要调用系统调用并给定执行函数和参数,线程可以有返回值。

(4)return、系统调用exit会终止当前、所有线程。显示调用pthread_exit也会终止线程。二者的区别是主线程调用前者会终止进程内所有线程,后者只会终止主线程。

二、线程调度

​ 线程的执行总是趋向于CPU受限或IO受限。而调度器会为IO受限的线程提供更高的动态优先级。调度器会尽量使一个线程在一个特定的CPU上运行,这样可以提高cache命中率以及高效使用内存,当一个CPU过于繁忙时,调度器也将线程迁移至空闲CPU运行。

名称说明作用
动态优先级可以被调度器实时调整(在静态优先级的基础上得到)决定线程的运行顺序
静态优先级只可以由应用程序指定,默认为0决定CPU时间片的大小

​ 线程会按照动态优先级的大小排列在激活的优先级阵列中。当一个线程已经占用了较长的CPU时间(T<=时间片大小),那么该线程就会被排入过期的优先级阵列,在其后的线程则会被放在CPU上运行。当激活的阵列已经没有等待线程时,会将激活阵列与过期阵列进行身份互换,继续运行新激活阵列上的线程。
在这里插入图片描述
​ 线程会因为等待某个事件或条件的发生而加入到对应的等待队列中,并随即进入睡眠状态。当事件发生时,内核会通知对应的等待队列中的所有线程,这些线程会被唤醒并被转移到适当的运行队列中。

状态名描述
可中断的睡眠状态睡眠直到某个条件变为真,如产生一个硬件中断、释放正在等待的系统资源或是传递一个信号。
不可中断的睡眠状态只能被如硬件中断、正在等待的系统资源被释放等唤醒,对其他进程传递的信号不响应。

在这里插入图片描述

三、线程实现模型
  • 用户级线程模型

​ 线程由用户级别的线程库全程管理。这些线程存储在进程的用户空间,内核无法感知。线程的创建、终止、切换全部在用户态下完成。然而由于线程无法被内核调度,所以该进程被调度器视为一个无法分割的整体单元,无法实现多线程并发以及CPU负载均衡。它实现的实际上是一个多用户级线程对应一个内核调度实体(M:1)。

  • 内核级线程模型——Linux

​ 线程由内核负责管理。应用程序对线程的创建、终止、同步都必须通过内核提供的系统调用完成,所以操作系统无需在线程库级别管理线程。然而内核创建大量调度实体与线程对应,会用到更多的内核资源,同时内核的线程管理成本要比用户级线程管理高很多,线程创建、切换、同步耗费的时间也更高,给内核调度器带来巨大负担。它实现的实际上是每一个用户级线程对应一个内核调度实体(1:1)。

  • 两级线程模型——Go

​ 线程由内核与线程库共同管理。一个进程可以关联多个内核调度实体,而进程中的线程却不与其一一对应,这些线程可以映射到同一个已关联的内核调度实体上。即先通过操作系统内核创建多个内核级线程,通过这些内核级线程对用户级线程进行调度。它实现的实际上是多个用户级线程对应多个内核调度实体(M:N)。Go中称用户级线程为goroutine
在这里插入图片描述

四、线程同步

​ 由于一个进程所拥有的相当一部分虚拟内存地址都可以被该进程中的所有线程共享,为保障共享数据的一致性,引入临界区概念。即只能被串行化访问或执行的某个资源或代码段。通过采用互斥量、原子操作这类同步工具保证临界区有效。

  1. 互斥量

​ 在同一时刻,只允许一个线程出于临界区内的约束称为互斥。每个线程在进入临界区之前,都必须先锁定某个对象,只有成功锁定该对象的线程才可以进入临界区,否则阻塞。这个对象就称为互斥量

​ 互斥量分为初始化—(未锁定状态)—锁定—(已锁定状态)—解锁—(未锁定状态)。每个互斥量保护的临界区应该在合理范围内并且尽可能的大,但如果多个线程频繁出入较大临界区并且发生冲突,则应考虑切分该临界区并使用不同互斥量加以保护。注意在不同互斥量保护的临界区不应该包含对同一个资源的同种(不同)操作。这将导致多个进程可以通过不同的互斥量进入同一临界区。

​ 互斥量的出现导致的唯一问题就是死锁。一般通过“试锁定-回退”或者“固定顺序锁定”解决。前者在锁定多个锁失败时,会解锁之前的互斥量,并重新尝试加锁;后者规定所有线程上锁的顺序,永远是锁定了1才可以锁定2。

  1. 条件变量

​ 条件变量与互斥量组合使用。当对应的共享数据状态发生变化时,通知其他因此而被阻塞的进程。

操作作用
等待通知(wait)阻塞当前线程,直至收到该条件变量发来的通知
单发通知(signal)该条件变量向至少一个正在等待它通知的线程发送通知
广播通知(broadcast)该条件变量给正在等待它通知的所有线程发送通知

注意:(1)等待通知操作在临界区内进行,即线程获取到互斥量后,发现临界区的值不符合条件,所以解锁互斥量并阻塞该线程。

​ (2)等待通知(解锁互斥量,阻塞当前线程)是个原子操作。阻塞之后该线程会一直等待条件变量通知,并尝试再次锁定。

五、线程安全

​ 线程安全:一个代码块,可以被多个线程并发执行,并且总能达到预期效果,则认为是线程安全。

​ 可重入函数:一个函数,如果多个线程并发的调用的结果,和它们以任意顺序依次调用的结果总是相同的,则认为是可重入函数。如果一个函数把共享数据作为它返回的结果或者包含在它返回的结果中,它一定不是一个可重入函数。

​ 程序性能指标:响应时间和吞吐量。

​ 程序的正确性和可伸缩性:后者是指增加CPU核心数的情况下,其运行速度不会受到负面影响(在多CPU并行的条件下,实现互斥量之类的串行操作,需要内核、CPU共同协调,CPU核心越多,协调工作越复杂)。如何在平衡二者的关系?

  • 控制临界区纯度:临界区代码只包含操作共享数据的代码
  • 控制临界区粒度:粒度过细会增加底层协调工作的次数,所以将几段操作同一共享数据的临界区合并。
  • 减少临界区代码执行耗时:对一个包含操作不同共享数据的临界区,应将其分为多个临界区;同时改进算法。
  • 避免长时间持有互斥量:在临界区中代码会等待某个共享数据的情况,引入条件变量来适时对该互斥量进行解锁与锁定。
  • 优先使用原子操作而不是互斥量

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

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

相关文章

对象实体 参考标准

1usingSystem;2usingSystem.Data;34namespaceFramework.Components5{ 6 /**//// <summary> 7 /// 公告通知实体 8 /// </summary> 9 public class NoticeInfo 10 { 11 基础信息-------------------------------------------------------…

博客园贵团队可以给个解释么?

发表了一片文章&#xff0c;被博客园团队移除出首页&#xff0c;自认为没有违反规定&#xff0c;于是回复该消息&#xff0c;想询问原因&#xff0c;但是一直没得到回复&#xff0c;请问这是为什么呢&#xff0c; 为什么那么久了还是未读状态&#xff0c;为什么从来不给回复&am…

unity, 颜色随高度渐变shader

一&#xff0c;颜色随世界空间高度渐变。 Shader "Custom/heightGradual_worldSpace" { Properties { _Color ("Color", Color) (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) "white" {} _Glossiness ("S…

IBM如何拥抱Spark

Spark是目前相当火热的开源计算框架&#xff0c;相对于Hadoop&#xff0c;Spark优势是高性能和易用性。Spark的高性能源于其采用内存储存数据&#xff0c;应用可以以内存的速度进行运算&#xff1b;Spark的易用性在于通用的API&#xff0c;用户可以编写复杂的并行计算程序&…

arcgis js 4.x 地图中加入图片

arcgis js 4.x版本&#xff0c;如何加入图片问题&#xff1a;如何将自定义图片放入到arcgis的图层当中&#xff1f;本人在网上查找的方法中&#xff0c;发现大部分方法只适用于3.x版本&#xff0c;只有一种引入自定义BaseDynamicLayer的方法可用&#xff0c;然而按照这种方式&a…

对你的的应用程序进行Debug

对你的的应用程序进行Debug 介绍如何使用Microsoft Visual Studio Code Name "Orcas" Beta 1对基于Silverlight的应用程序进行debugging .在Silverlight中debugging所使用的工具和技巧和其它的 Visual Studio projects是类似的. 想查看更多的关于debugging信息的, 查…

在.Net如何制作自定义的快捷方式(转)

我们用.Net安装程序生成的快捷方式是这样的&#xff0c;如下图&#xff1a;该图中目标所对应的文本框是灰色的&#xff0c;并且下方的查找目标和更改图标两个按钮也是不可用。这样我们根本就没有办法更改这个快捷方式。假如这时有个客户需要在程序启动的时候传入一些参数&#…

大数据——Kafka学习笔记

具体代码可以参考&#xff1a; https://github.com/Ostrich5yw/java4BigData/tree/master/java4Kafka

大数据——SparkCore学习笔记

Spark 一、Spark简介 Spark 是一种由 Scala 语言开发的快速、通用、可扩展的大数据分析引擎Spark Core 中提供了 Spark 最基础与最核心的功能Spark SQL 是 Spark 用来操作结构化数据的组件。通过 Spark SQL&#xff0c;用户可以使用 SQL 或者 Apache Hive 版本的 SQL 方言&am…

Kubernetes权威指南精彩段落

2019独角兽企业重金招聘Python工程师标准>>> 看到上述两段代码&#xff0c;你可能会有一种“开门复动竹, 疑是故人来”的感觉。的确&#xff0c;这段代码经笔者反复考证后认定&#xff1a;100%高仿kubernetes Controller Server中的代码。连传说中的谷歌大神也能cop…

大数据——SparkSQL学习笔记

Spark 一、SparkSQL简介 ​ Spark用来处理结构化数据的一个模块&#xff0c;它提供了两个编程抽象分别叫做DataFrame和DataSet&#xff0c;它们用于作为分布式SQL查询引擎&#xff08;类似于Hive&#xff0c;为便于进行MapReduce操作而使用类SQL语句进行Spark操作&#xff09…

用SD卡下载uboot、linux内核和文件系统

1、 移植mtd-utils: a) 下载utd-utils 下载地址为ftp://ftp.infradead.org/pub/mtd-utils/b) 交叉编译mtd-utilsi 修改Makefile CROSSarm-linux-ii makeiii 查看下mtd-utils-1.0.0目录下是否生成了咱们所需要大工具 (flashcp,nandwrite......等)。有工具生成了&#xf…

css3中变形与动画(三)

transform可以实现矩阵变换&#xff0c;transition实现属性的平滑过渡&#xff0c;animation意思是动画&#xff0c;动漫&#xff0c;这个属性才和真正意义的一帧一帧的动画相关。本文就介绍animation属性。 animation属性通过一些关键帧中元素属性的改变来实现动画效果。当然也…

Scott Mitchell 的ASP.NET 2.0数据教程之四十四::DataList和Repeater数据分页

原文 | 下载本教程中的编码例子 | 下载本教程的PDF版 导言 分页和排序是显示数据时经常用到的功能。比如&#xff0c;在一个在线书店里搜索关于ASP.NET 的书的时候&#xff0c;可能结果会是成百上千&#xff0c;而每页只列出十条。而且结果可以根据title&#xff08;书名&#…

通过ClassLoader调用外部jar包

通过ClassLoader调用外部jar包 我们大家都知道&#xff0c;每个运行中的线程都有一个成员contextClassLoader&#xff0c;用来在运行时动态地载入其它类。 系统默认的contextClassLoader是systemClassLoader&#xff0c;所以一般而言java程序在执行时可以使用JVM自带的类、$JAV…

Git回滚操作的总结

git结构和各操作之间的关系 1&#xff0c;撤销add操作&#xff1a; git reset 2&#xff0c;撤销commit操作&#xff1a; git reset –soft 保留源码&#xff0c;只回退commit信息到某个版本&#xff0c;不涉及index的回退&#xff0c;如果还需要提交&#xff0c;直接commit即…

Blender建模与游戏换装(转载文)

本文转载自https://my.oschina.net/huliqing/blog/880113?hmsrtoutiao.io 如果本文涉及侵权行为&#xff0c;请原作者联系博主邮箱&#xff0c;我将及时进行删除处理 博主邮箱&#xff1a;yibiandaoaliyun.com 前言 本文将详细讲解3D游戏中换装的原理及换装中的一些重点问题&a…

出路在哪里?出路在于思路!智者无敌

有人工作&#xff0c;有人继续上学&#xff0c;大家千万不要错过这篇文章&#xff0c;能看到这篇文章也是一种幸运&#xff0c;真的受益匪浅&#xff0c;对我有很大启迪&#xff0c;这篇文章将会改变我的一生&#xff0c;真的太好了&#xff0c;希望与有缘人分享&#xff0c;也…

xml02 XML编程(CRUD)增删查改

XML解析技术概述 Demo2.java import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; public class Demo2 { public static void main(String args[])throws Exception { //1.创建工程 DocumentBuilderFac…

ASP.NET Web Game 架构设计1--服务器基本结构

ASP.NET Web Game 架构设计1--服务器基本结构 1. 基本结构图 2. 系统组成与角色 整个系统大体上分为三个部分&#xff1a;1.网页客户端。2.IIS Web服务器。3.数据库及逻辑服务器。其中Web服务器不处理任何逻辑&#xff0c;它的作用只有两点&#xff1a;1.承载用户。…