C#多线程编程序--聊聊线程
这篇文章主要给您讲解几个基本问题,什么是线程?为什么要用线程?线程万能?这几个问题。我这篇博客是在该系列另外几篇博客之后写的,之所以不往下继续写,而是回到最初的问题,是因为我感觉到我没有很好的讲解开头的部分,没有很好的介绍线程的基础知识,因此有了写这篇博客的想法。本文不会一五一十的介绍线程,那是百度百科和维基百科的事,我的目的是和您坐下来聊一聊,以我自己粗浅的理解,给您简单讲解一下线程的相关内容。读完,您会对线程有个基本的了解,然后你再去看本系列的其他部分,就会简单些,不会一头雾水。
什么是线程?为什么要用线程?
在一个pc中有很多应用,每一个应用都被分配了一块内存,这些内存就是进程。当你在桌面点击不同的应用时,cpu会在这些应用中切换,以保证尽快的响应你的操作。这些进程能够独立运行,彼此互不影响,一个进程出了问题不会影响其他的进程。很多程序为了提升用户的操作体验,会有好几个进程,要开启一个新进程要消耗很多的时间(大概几秒),有没有一个“轻量级”的进程,能让cpu执行它,且不需要那么多的内存?这就是线程。线程相对进程要简单的多,分配一个新线程很快。现在的cpu执行都是以线程为单位来调度的,而不是进程,并且多核处理器可以并行执行多个线程。
线程万能?
线程怎么看都比进程要好很多,那么线程有什么缺点?相对于进程,线程的调度有很多的优势。这就导致有人对线程过分高估,干点什么事都新开个线程,期待它会提高用户体验。殊不知线程的创建和切换也会消耗资源。一个线程栈大概1m,切换线程需要cpu从一个线程上下文保存起来,以备以后再次调用该线程。然后读取想要切换的线程的上下文,如果新建线程,还要分配线程的内存。当频繁创建和切换线程很频繁,或者切换线程后执行的人无很短,这些消耗就必须要考虑了。
线程的消耗主要集中在创建和线程切换。非常快的任务是不适合调派其他线程来执行的。而是那些需要等待的任务才适合交给其他线程来执行。如链接其他服务,文件读写等IO操作,再者就是长时间的计算,这些任务如果都在主线程执行,会造成“卡顿”,这样的卡顿是让人沮丧的,如果卡顿的时间过长,我们会以为我们的电脑死机了。此时如果将这样的任务交给另一个线程去执行,而主线程能够继续响应用户其他的操作,这就能提升用户体验,线程的消耗才是“物超所值”。另一个消耗是创建线程的消耗。当创建一个新线程,并执行结束后,这个线程就再也不会唤醒。可以把这些死线程利用我来,当真正需要新线程的时候再创建新线程。做法是把线程统一管理,重复利用,这就是线程池。
线程的两大消耗已经有了解释,线程还有一个问题就是数据共享的问题。我们说过,线程很轻量级,为了使线程够轻,采用的办法是多个线程共享一个进程的内存,这就会导致多个线程执行时,数据会产生不同步的问题。这个线程已经修改了某一个数据,另一个线程并没有读取到该数据,还是按老值来操作。
线程同步的解决办法有两个,一是原子操作,另一个是锁。原子操作是一组API,该API能够保证该操作的“原子性”,所谓原子性,就是其他线程对同样资源的访问都会在之前或者之后发生,比如对某一数据的读操作,如果该操作是原子的,那么就是说所有对该资源的写操作都是在该读操作的之前或者之后发生,而不会发生正在读该数据时,其他线程完成了对该资源的写操作,对该数据的读总是读到最新的。这样的操作的优点很明显,简单,且不阻塞线程,不会造成死锁。其缺点是能够实现的功能有限。
另一个线程同步的方法是锁,锁的原理是在不想被并发执行的代码的周围加上一个锁,类似这样:
var m_lock = new SomeLock();
m_lock.Enter();
//some code
m_lock.Leave();
当有线程执行到m_lock.Enter()时,其内部是一个变量(比如bool型),会将该变量置为true,当其他线程走到m_lock.Enter时,看到变量为true,要么不断尝试,要么挂起,等待锁被释放后,被唤醒。当执行完some code后,m_lock.Leave()执行,会将变量置为false,这样其他线程就可以访问该段代码。锁的种类大致分为三种,1是自旋锁,当执行到m_lock.Enter()时,发现被锁定,会不断尝试获得锁,像这样:
//比如这个i就是那个bool型变量
//注意,本例是简单讲解,实际的锁,此处应调用原子操作,如Interlocked中的方法,或者将变量i设为volatile。
while(i == true){
//一些黑科技
}
线程会不断的while,一直循环,直到i==false,表示锁被释放了,他才继续执行。这种锁的优点是单线程时执行非常块,但是在等待锁释放时,会不停的自旋,以求最快的进入锁,这会白白的浪费CPU。
2 内核锁,内核锁也是一个变量,只不过这个变量不用你手动的去改变,而是由系统内核来对其进行维护。这种锁的优点是当其他线程尝试进入锁,而该锁已被锁定时,会阻塞该线程,然后内核负责在锁释放后,唤醒该线程,这会节约CPU资源,在锁被释放之前,线程一直挂起,用来执行其他操作。但是其缺点就是当单线程时,由于内核锁是内核构造,因此用户线程需要切换到内核中,读取该变量,然后再切换回用户线程,最后才能得到返回值,这一系列的操作造成了资源的消耗,所以很慢。如果该资源的大部分时间都是单线程,并且通常锁定的时间都很短,那么用自旋锁就比内核锁更合适,相反就用内核锁。
3 混合锁,混合锁结合了12两种锁的优点,单线程时很快,多线程时阻塞,还有多线程时先自旋一小段时间,如果被锁定的资源很快被释放,那么久不需要调用内核锁,否则调用内核锁。我们经常会见到 lock(objec)语句,其内部是调用Monitor.Enter和Monitor.Leave,这个 Monitor就是个混合锁。
上面讲了这几种锁,各有优缺点。在多线程编程中,基本原则是尽量将代码设计的合理些,减少锁的使用,若必须使用锁,则根据自身的情况,选择合理的锁。
以上,我介绍了线程的基本知识和线程安全的相关知识,若您对其中的内容有任何不懂得地方,欢迎在评论区与我互动。
C#多线程编程序--聊聊线程的更多相关文章
- [转]c++多线程编程之pthread线程深入理解
多线程编程之pthread线程深入理解 Pthread是 POSIX threads 的简称,是POSIX的线程标准. 前几篇博客已经能给你初步的多线程概念.在进一 ...
- 多线程编程之pthread线程深入理解
不同的平台和操作系统上 进程和线程的实现机制不完全一致 但是一般来说线程栈都是独立的 只要得到地址就可以相互访问 Pthread是 POSIX threads 的简称,是POSIX的线程 ...
- posix 线程(一):线程模型、pthread 系列函数 和 简单多线程服务器端程序
posix 线程(一):线程模型.pthread 系列函数 和 简单多线程服务器端程序 一.线程有3种模型,分别是N:1用户线程模型,1:1核心线程模型和N:M混合线程模型,posix thread属 ...
- 线程模型、pthread 系列函数 和 简单多线程服务器端程序
一.线程有3种模型,分别是N:1用户线程模型,1:1核心线程模型和N:M混合线程模型,posix thread属于1:1模型. (一).N:1用户线程模型 “线程实现”建立在“进程控制”机制之上,由用 ...
- C#多线程之旅(3)——线程池
v博客前言 先交代下背景,写<C#多线程之旅>这个系列文章主要是因为以下几个原因:1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的,如果没有用好,容易造成很 ...
- QT核心编程之Qt线程 (c)
QT核心编程之Qt线程是本节要介绍的内容,QT核心编程我们要分几个部分来介绍,想参考更多内容,请看末尾的编辑推荐进行详细阅读,先来看本篇内容. Qt对线程提供了支持,它引入了一些基本与平台无关的线程类 ...
- [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...
- iOS 多线程编程之Grand Central Dispatch(GCD)
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...
- python并发编程之Queue线程、进程、协程通信(五)
单线程.多线程之间.进程之间.协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯.或者说为了解耦,普遍采用Queue,生产消费模式. 系列文章 python并发编程之threading线程(一 ...
随机推荐
- Linux目录结构及作用
/:根目录 /bin:存放基础系统所需的最基础的命令(程序) binary 比如:ls.cp.mkdir等 功能和/usr/bin类似,这个目录中的文件都是可执行的,普通用户都可以使用的命令 /b ...
- php环境下所有的配置文件以及作用
以下主要是针对linux下的目录(windows也是一样,文件名都一样) Apache:etc/httpd.conf PHP:etc/php.ini (Apache 正在运行的 PHP 版本) M ...
- json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值
一.json相关概念 json,全称为javascript object notation,是一种轻量级的数据交互格式.采用完全独立于语言的文本格式,是一种理想的数据交换格式. 同时,json是jav ...
- 长整形的使用及cin加速
_int64 和 long long 那么对ACMer来说,最为关心的就是在各个OJ上交题应分别使用哪种方式了.其实方式只有有限的几种: 如果服务器是linux系统,那么定义用long long,IO ...
- Spring 代理对象,cglib,jdk的问题思考,AOP 配置注解拦截 的一些问题.为什么不要注解在接口,以及抽象方法.
可以被继承 首先注解在类上是可以被继承的 在注解上用@Inherited /** * Created by laizhenwei on 17:49 2017-10-14 */ @Target({Ele ...
- ANTD mobile源码分析 -- popover
最近的开发中要用到很多的各式各样的组件.但是发现ant design mobile(后面简称ANTDM)里很多的资源.于是就分析一下,学习学习. ANTDM直接使用了typescript,没有用ES2 ...
- nginx的环境配置的问题
在安装好nginx之后,运行nginx,报错: nginx dyld: Library not loaded: /usr/local/lib/libpcre.1.dylib Referenced fr ...
- Python中从B类中调用A类的方法。
好久没上了,Python还在学--最近进度有点慢... 下面代码记录了一个不太好理解的点,自己写了个小例子,总算是理顺了. B类想要调用A类,自己在网上看了一下其他人的回复:创建A类的实例,直接调用这 ...
- word自动备份,word误删内容恢复
有个问题时长困扰着我,就是一次不小心把word里面的一部分内容误删了之后,又手残点击ctrl+s给保存了,要是立即ctrl+z还能撤销,可要是关闭了word才想起来撤销就来不及啦,现在终于找到解决的办 ...
- 【前端】Vue和Vux开发WebApp日志一、整合vue+cordova和webpack+gulp
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/vue_vux.html 项目github地址:https://github.com/shamoyuu/vue-vu ...