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线程(一 ...
随机推荐
- java中的Collection集合类
随着1998年JDK 1.2的发布,同时新增了常用的Collections集合类,包含了Collection和Map接口.而Dictionary类是在1996年JDK 1.0发布时就已经有了.它们都可 ...
- AGC010 - D: Decrementing
原题链接 题意简述 给出一个个数的序列,足够聪明的AB两人轮流进行以下操作: 令一个大于1的数减1,然后所有数除以. 如果一个人不能操作了,那么他就输了. 输入保证所有数都是正整数并且. 分析 这是一 ...
- SpringBoot实战 之 异常处理篇
在互联网时代,我们所开发的应用大多是直面用户的,程序中的任何一点小疏忽都可能导致用户的流失,而程序出现异常往往又是不可避免的,那该如何减少程序异常对用户体验的影响呢?其实方法很简单,对异常进行捕获,然 ...
- Hive语法
1.Select 语法 SELECT [ALL | DISTINCT] select_expr, select_expr, ... FROM table_reference [WHERE where_ ...
- ARM开发软件ADS教程
ARM开发软件ADS教程 ADS(ARM Developer Suite)是ARM公司推出ARM集成开发环境,操作简单方便,获得广大开发人员的青睐.下面使用ADS v1.2做一个实例教程,帮助大家学会 ...
- 使用xfire搭建webService服务
后边有个项目需要接入4A,要用到webService服务,暂时还不确定是不是会有我的事,但为了有备无患,还是抽时间学习了以下相关的知识. 本来我所了解到的发布webService服务有用cxf和xfi ...
- php simpleXML操作xml的用法
XML简介 XML是一种流行的半结构化文件格式,以一种类似数据库的格式存储数据.在实际应用中,一些简单的.安全性较低的数据往往使用 XML文件的格式进行存储.这样做的好处一方面可以通过减少与数据库的交 ...
- Activiti 实战篇 小试牛刀
原文地址:http://blog.csdn.net/qq_30739519/article/details/51166062 1:工作流的概念 说明: 1) 假设:这两张图就是华谊兄弟的请假流程图 ...
- Error Code: 1054. Unknown column 'age' in 'user'
1.错误描述 10:28:20 alter table user modify age int(3) after sex Error Code: 1054. Unknown column 'age' ...
- VxWorks启动过程详解(上)
vxworks有三种映像: VxWorks Image的文件类型有三种 Loadable Images:由Boot-ROM引导通过网口或串口下载到RAM ROM-based Images(压缩/没有压 ...