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,一经查实,立即删除!

相关文章

maven必知必会

目录 了解mavenmaven的作用maven仓库本地配置添加远程仓库依赖搜索顺序定制包到本地仓库pom文件依赖管理原则构建声明周期插件了解maven maven的作用 maven采取约定大于配置的原则,规范了一套标准的javaweb项目结构maven提供了完备的包管理功能,不用到处找jar包了maven提供了一…

lecture 4 : More Objective-C

Creating Objects 这件事困扰我一点时间了&#xff0c;ObjC没有一个Constructor的概念 而在Create Objects这件事上既有用过自己写的-init&#xff0c;还return instancetype&#xff0c;大概这个&#xff0c;也有用过一些Class Method&#xff0c;就是明确知道是id类型的&…

对象实体 参考标准

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

SerialPort comstat is being used without defining

Run-Time Check Failure #3 - The variable comstat is being used without being initialized. 参考&#xff1a;http://blog.sina.com.cn/s/blog_5d2412000100ojx3.html 方案1: 改变项目配置属性 一种解决方案是改变基本运行时检查&#xff08;changing the runtime checks i…

Leetcode:27. 移除元素

力扣题目链接 解题思路 首先很容易想到暴力解法,用两个for循环,第一个for循环用来遍历整个数组,第二个for循环用来更新数组.但这种解法的时间复杂度为O(n^2) 因此考虑双指针思想,通过一个快指针和慢指针在一个for循环下完成两个for循环的任务,其中,快指针用来寻找新的元素,即…

【原】简单shell练习(四)

1.查看已开启端口信息 #ss -ln 2.列出谁在使用某个端口&#xff08;如&#xff1a;80&#xff09; #lsof -i:80 3.显示文件夹下文件信息 #find /home/root -type f#find -type f 4.磁盘大小信息 #df -h #du -sh * 5.查看一个文件夹下文件总个数 # ls -l |wc -l 6.查看进程是否…

JavaScriptWindow使用对象

窗口对象的属性和方法&#xff1a;格式&#xff1a;[window.]属性[window.]方法&#xff08;参数&#xff09;opener.属性opener.方法&#xff08;参数&#xff09;self.属性self.方法&#xff08;参数&#xff09;parent.属性parent.方法&#xff08;参数&#xff09;top.属性…

无法在web服务器上启动调试 您不具备调试此应用程序的权限

一般用下面的方法可以解决: 1&#xff1a;确认在“配置属性”中的“启用ASP.NET调试"为"True" 2&#xff1a;确认你的"web.config"中的"debugtrue" 3&#xff1a;若你安装过Win2000 SP4后&#xff0c;则要在命令行执行"regsvr32 i asp…

Go学习笔记—Go并发基础

Go并发基础 并行&#xff1a;程序在任意时刻内都是同时运行的 并发&#xff1a;程序在单位时间内都是同时运行的 ​扇入&#xff1a;多条通道聚合到一条通道中&#xff08;select聚合&#xff0c;加密解密服务&#xff09; ​扇出&#xff1a;一条通道发散到多条通道中&#x…

史蒂夫乔布斯6月斯坦佛大学演讲: 必须找到你所钟爱的东西

博客搬家咯&#xff5e; http://joeleee.github.io/ 博客搬家咯&#xff5e; http://joeleee.github.io/ 博客搬家咯&#xff5e; http://joeleee.github.io/ 关于如何将生命中的点点滴滴串联起来&#xff0c;关于爱和损失&#xff0c;关于死亡&#xff0c;乔布斯如是说. h1 ! …

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

发表了一片文章&#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…

WinForm给ComboBox增加Value(转)

做一个图书管理系统,用到了combobox, 天呀,竟然不能像DropDownList那样直接使用键值对的方式 百度了半天,终于找到方法,发出来大家共享 用DataTable可以&#xff01;但是总不能象男&#xff0c;女这样两项也用一个DataTable吧&#xff0c; 这也太麻烦了啊&#xff01; 用Hashta…

Go学习笔记—Channel通道

Go并发通信——Channel ​ Go语言的并发模型是CSP&#xff08;Communicating Sequential Processes&#xff09;&#xff0c;提倡通过通信共享内存而不是通过共享内存而实现通信。&#xff08;DO NOT COMMUNICATE BY SHARING MEMORY; INSTEAD, SHARE MEMORY BY COMMUNICATING.…

【转载】程序员技术练级攻略

月光博客6月12日发表了《写给新手程序员的一封信》&#xff0c;翻译自《An open letter to those who want to start programming》&#xff0c;我的朋友&#xff08;他在本站的id是Mailper&#xff09;告诉我&#xff0c;他希望在酷壳上看到一篇更具操作性的文章。因为他也是喜…

FileSystemObject (FSO)对象方法总结及应用

FileSystemObject (FSO)组件可以用来处理系统驱动器&#xff0c;文件夹&#xff0c;和文件。因为它是一个ActiveX控件&#xff0c;所以它能被js&#xff0c;vbs等文件使用&#xff0c;以实现对机器文件系统的操作。 下面将总结一下FSO中的对象和方法&#xff0c;其实FSO中大多数…

IBM如何拥抱Spark

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

SQL语句导入导出大全

SQL语句导入导出大全/******* 导出到excelEXEC master..xp_cmdshell ’bcp SettleDB.dbo.shanghu out c:\temp1.xls -c -q -S"GNETDATA/GNETDATA" -U"sa" -P""’ /*********** 导入ExcelSELECT * FROM OpenDataSource( ’Microsoft.Jet.OLEDB…

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信息的, 查…