一、开篇概念明晰:

多任务:

  • 协作式多任务:cpu可以处理多种任务,但是这些任务是排队等候的,当cpu在处理一个任务的时候,其他的任务被锁定,只有当cpu处理完当前任务,才可以继续处理下一个任务(专一暖男);
  • 抢占式多任务:一个任务正在执行,可以被强行中断挂起,去执行其他的任务(花心大萝卜)。

进程与线程:

  • 进程:内存和资源的物理分离成为进程。分配给进程的内存只有所属的进程才可以访问。一个应用程序可以启动多个进程
  • 线程:开发架构将程序中的一部分进行分离,使被分离的部分与程序的其余部分执行顺序不一致的操作。(在计算机中,程序的运行时由程序计数器决定的,程序计数器就像是一个指针,指定了应用程序下一步需要执行的指令。)
  • 进程与线程:一个进程启动,默认会有一个主线程,但是一个进程可以对应多个线程。
  • 时间片:处理器分配给线程的执行时间。一个处理器一次只能处理一个线程,所谓的多任务(抢占式)就是处理器在快速切换执行不同的线程。若是有多个处理器就不一样了。(自我入宫以来以为可以独得皇上宠爱,没想到皇上要雨露均沾)。

中断:

前置知识点:

1、进程是内存和资源的物理分离,只有所属线程才能访问;

2、一个cpu给一次只能执行一个线程,cpu给每一个线程分配时间片,多线程就是在不同线程之间快速切换。

问题:进程间相互独立且不可访问,那么,cpu是怎么进行线程切换的,也就是问:一个线程正在执行,它要怎么知道要中断挂起,给其他线程来执行。

答案:Windows本身(其实也是处理器上正在运行的一个程序)有一个主线程----系统线程,负责其他线程的调度。

线程本地存储器(Thread Local Storage,TLS):存储线程的状态信息。当一个线程执行的时间片到期的时候,需要存储下线程当前的状态信息,以确保在他被分配的下一个时间片可以正常的执行。TLS包含了:

寄存器、堆栈指针、调度信息、内存中的地址空间和其他资源的使用信息。

其中寄存器中有一个是程序计数器,存放了线程接下来应该执行的指令。(CPU执行的指令的都是从寄存器读取的)

中断:中断是一种机制,它能够使CPU指令的正常顺序执行转向计算机内存中的其他地方,而不需要知道目前正在执行什么程序。解释如下:

1、程序要开始执行一个线程之前:系统线程先决定线程要执行多长时间,and在当前线程的执行序列中放置一条中断指令。疑问:不确定这个指令是在时间片到了之后插入的还是在线程开始之前预先插入的,但推测是等待时间片要到的时候插入的,因为程序执行的指令并不是容易预测的,不同的数据不同走不同的逻辑分支,程序的执行是一边编一边走的(会先编译的快一些)而不是编译好所有的逻辑分支的指令,等待程序执行的时候根据数据进行选择,所以个人觉得很难预测要走哪一个逻辑分支,很难提前太早插入中断指令。

2、程序开始执行一个线程:读取TLS中线程的程序计数器,把该程序计数器的指令指向的地址从TLS中拖拽出来插入到CPU执行的指令集合中,同时把TLS中的堆栈信息加载到CPU的其他寄存器中。线程开始执行

3、当碰到中断指令时:存储当前线程的堆栈信息,记录当前线程的程序计数器数据,记录其他资源的信息,存储入TLS,把当前线程放入线程队列的末尾,返回到线程队列的开头准备执行队列的第一个线程,回到步骤1。

线程睡眠:线程退出执行队列一段时间称为睡眠。有时一个线程的执行需要一定的资源,但是当线程开始执行时,这个资源并没有生成或者正在被使用,因此线程需要等待一段时间。

时钟中断:一个线程进入睡眠是它会再次被打包放入TLS中,不过并不是放置在了TLS的末尾,而是放入了一个独立的睡眠队列中,为了时睡眠队列上的线程再次运行,需要使用另一种中断了标记他们,成为时钟中断。当一个睡眠的线程可以执行的时候,它才会被放入到可运行的线程队列中,的末尾。

 线程终止:

  1. 线程执行结束,线程终止;
  2. 在执行另外一个线程的过程中,用一个请求显示的停止线程。

线程终止时,线程的TLS会释放其内存。

二、线程的创建:
直接贴代码:

1、创建线程:

2、使用线程创建线程:

        public override void DoExecute()
{
base.DoExecute();
Thread mainThread = new Thread(new ThreadStart(MainThread));
AddLog("current main thread's state is " + mainThread.ThreadState);
mainThread.Start();
AddLog("current main thread's state is " + mainThread.ThreadState);
} private void FirstThread()
{
AddLog("FirstThread start~");
for (int i = ; i < ; i++)
{
AddLog("FirstThread index~ "+i);
} AddLog("FirstThread stop~");
} private void ThecondThread()
{
AddLog("ThecondThread start~"); for (int i = ; i < ; i++)
{
AddLog("ThecondThread index~ " + i);
} AddLog("ThecondThread stop~");
} private void MainThread()
{
AddLog("MainThread start~"); Thread firstThread = new Thread(new ThreadStart(FirstThread));
Thread secondThread = new Thread(new ThreadStart(ThecondThread));
firstThread.Start();
secondThread.Start(); for (int i = ; i < ; i++)
{ } AddLog("thecondThread state " + secondThread.ThreadState);
AddLog("MainThread stop~");
}

3、线程的睡眠和恢复:

使用属性:

ThreadState:ThreadState是一个枚举类型,表示线程的当前状态,当线程睡眠的时候线程状态值为ThreadState.WaitSleepJoin;

注意一个类似的属性:IsAlive (获取指示当前线程的执行状态的值)如果此线程已经开始但尚未正常终止或中止,则为 true,否则为 false。所以当线程睡眠的时候,isAlive仍然为true;

使用方法:

  • Sleep(int millisecondsTimeout);   millisecondsTimeout表示使线程睡眠的毫秒数;
  • Interrupt();      中断处于 WaitSleepJoin 线程状态的线程。

测试代码:

        public static void SleepThread()
{
Thread newThread = new Thread(new ThreadStart(PrintNo));
newThread.Name = "new thread";
newThread.Start(); while (true)
{
if (newThread.ThreadState == ThreadState.WaitSleepJoin)
{
Console.WriteLine("current thread state: " + newThread.ThreadState);
newThread.Interrupt();
break;
}
}
} static void PrintNo()
{
for (int i = ; i < ; i++)
{
Console.WriteLine("print " + i);
if (i == )
{
            //
try
{
Thread.Sleep();
}
catch (Exception ex)
{
Console.WriteLine("new thread interrupted"+ex.Message);
}
Console.WriteLine("current thread is " + Thread.CurrentThread.Name + ", state: " + Thread.CurrentThread.ThreadState);
}
}
}

结果:

...
print
print
print
print
print
print
print
print
print
print
current thread state: WaitSleepJoin
new thread interrupted
current thread is new thread, state: Running
print
print
print
print
print
print
print
print

Interrupt() 是对睡眠的线程提前唤醒的最好方法,需要注意的是使用这个方法会抛出异常需要捕获。

4、线程的中止(终止)和取消中止(终止):

使用方法:

  • Thread.CurrentThread.Abort(); 终止当前线程 --- 调用该方法线程将进入正在终止状态 ------  AbortRequested,
  • Thread.ResetAbort();  取消当前线程Abort的请求使线程继续执行。调用该方法线程将恢复
        public static void AbortThread()
{
Thread newThread = new Thread(new ThreadStart(PrintNo));
newThread.Name = "new thread for abort";
newThread.Start();
} static void PrintNo()
{
for (int i = ; i < ; i++)
{
Console.WriteLine("print " + i);
if (i == )
{
try
{
Thread.CurrentThread.Abort(); // 中断当前线程,会引发异常
}
catch (Exception ex)
{
Console.WriteLine("current thread is " + Thread.CurrentThread.Name + ", state: " + Thread.CurrentThread.ThreadState); Console.WriteLine("new thread Aborted" + ex.Message); // 取消当前线程请求的Abort();
//Thread.ResetAbort();
}
Console.WriteLine("current thread is " + Thread.CurrentThread.Name + ", state: " + Thread.CurrentThread.ThreadState); }
}
}

运行结果:

。。。
print 87
print 88
print 89
print 90
current thread is new thread for abort, state: AbortRequested
new thread Aborted正在中止线程。

如果取消上面对 Thread.ResetAbort(); 的注释,线程将不会终止,而是会继续执行。

5、使用join:
使用方法:join(),join是线程实例上的方法,当调用该方法的时候调用该方法的线程实例将进入WaitSleepJoin状态,直到当前线程执行完毕之后才开始继续执行线程实例所属的线程。
(我感觉理解起来有点绕,意思就是:有两个线程A和B,线程A需要在线程B之前执行,那么可以使用Join方法,在线程A内用线程B调用Join方法,这样可以使线程B进入WaitSleepJoin状态,线程A不变继续执行,当线程A执行完毕,B会开始执行。而如果有线程C,则线程C是不影响的)如下所示:

class ThreadTestForJoin
{
static Thread newThread;
static Thread newThread2;
static Thread newThread3;
public static void JoinThread()
{
newThread = new Thread(new ThreadStart(PrintNo));
newThread.Name = "new thread for join";
newThread.Start();
newThread2 = new Thread(new ThreadStart(PrintNo2));
newThread2.Name = "new thread be joined";
newThread2.Start();
newThread3 = new Thread(new ThreadStart(PrintThreadThree));
newThread3.Name = "我是勤劳的小画家";
newThread3.Start();
} static void PrintNo()
{
for (int i = ; i < ; i++)
{
Console.WriteLine("print " + i);
}
} static void PrintNo2()
{
newThread.Join();
for (int i = ; i < ; i++)
{
Console.WriteLine("print " + i);
}
} static void PrintThreadThree()
{
for (int i = ; i < ; i++)
{
Console.WriteLine("print " + Thread.CurrentThread.Name);
}
}
}

运行结果:

。。。
print 我是勤劳的小画家
print 我是勤劳的小画家
print 我是勤劳的小画家
print
print
print
print
print
print
print
print
print 我是勤劳的小画家
print 我是勤劳的小画家
print 我是勤劳的小画家
print 我是勤劳的小画家
print
print
print
。。。

C#线程--5.0之前时代(一)--- 原理和基本使用的更多相关文章

  1. java线程池系列(1)-ThreadPoolExecutor实现原理

    前言 做java开发的,一般都避免不了要面对java线程池技术,像tomcat之类的容器天然就支持多线程. 即使是做偏后端技术,如处理一些消息,执行一些计算任务,也经常需要用到线程池技术. 鉴于线程池 ...

  2. 并发编程学习笔记(14)----ThreadPoolExecutor(线程池)的使用及原理

    1. 概述 1.1 什么是线程池 与jdbc连接池类似,在创建线程池或销毁线程时,会消耗大量的系统资源,因此在java中提出了线程池的概念,预先创建好固定数量的线程,当有任务需要线程去执行时,不用再去 ...

  3. python并发编程之进程、线程、协程的调度原理(六)

    进程.线程和协程的调度和运行原理总结. 系列文章 python并发编程之threading线程(一) python并发编程之multiprocessing进程(二) python并发编程之asynci ...

  4. Jenkins使用总结,2.0 新时代:从 CI 到 CD

    Jenkins近阶段使用的总结篇,只写了个引子,却一直未动手写完,今天补上. 前几篇文章提到在内网jenkins直接构建部署升级线上环境,job都是暴露在外面,很容易被误操作,需要做简单的权限控制,以 ...

  5. Vue3.0工程创建 && setup、ref、reactive函数 && Vue3.0响应式实现原理

    1 # 一.创建Vue3.0工程 2 # 1.使用vue-cli创建 3 # 官方文档: https://cli.vuejs.org/zh/guide/creating-a-project.html# ...

  6. Java 线程池的介绍以及工作原理

    在什么情况下使用线程池? 1.单个任务处理的时间比较短 2.将需处理的任务的数量大 使用线程池的好处: 1. 降低资源消耗: 通过重复利用已创建的线程降低线程创建和销毁造成的消耗.2. 提高响应速度: ...

  7. Java 线程同步组件 CountDownLatch 与 CyclicBarrier 原理分析

    1.简介 在分析完AbstractQueuedSynchronizer(以下简称 AQS)和ReentrantLock的原理后,本文将分析 java.util.concurrent 包下的两个线程同步 ...

  8. JAVA线程及简单同步实现的原理解析

    线程 一.内容简介: 本文主要讲述计算机中有关线程的相关内容,以及JAVA中关于线程的基础知识点,为以后的深入学习做铺垫.如果你已经是高手了,那么这篇文章并不适合你. 二.随笔正文: 1.计算机系统组 ...

  9. hadoop入门(2)——HDFS2.0应用场景、原理、基本架构及使用方法

    一.HDFS概述         优点:高容错性.适合批处理.适合大数据处理.流式文件访问:一次写入,多次读取.         缺点:不适合低延迟数据访问.不适合小文件存取(受限于NameNode) ...

随机推荐

  1. ESLint学习小记

    一.关于配置文件,优先级从上到下: eslintrc.js .eslintrc.yaml .eslintrc.yml .eslintrc.json .eslintrc package.json 在官方 ...

  2. flask学习(一)

    特点: 短小精悍,可扩展性强 依赖wsgi:werkzurg werkzurg示例: from werkzeug.wrappers import Request, Response from werk ...

  3. Mac环境下Vagrant的安装

    1.安装Vagrant 下载地址:https://www.vagrantup.com/downloads.html 下载好pkg包后,点击安装即可. 2.安装 VirtualBox 下载地址:http ...

  4. [Linux]出错处理errno

    概述 公共头文件<errno.h>定义了一个整型值errno以及可以赋予它的各种常量. 大部分函数出错后返回-1,并且自动给errno赋予当前发生的错误枚举值. 需要注意的一点是,errn ...

  5. 高可用Redis(十):Redis原生命令搭建集群

    1.搭建Redis Cluster主要步骤 1.配置开启节点 2.meet 3.指派槽 4.主从关系分配 2.环境说明 两台虚拟机,IP地址分别为:192.168.81.100和192.168.81. ...

  6. loading js备份

    loadingManageEdit.jsp $(function(){ //组织 var lodingDeparts =[<c:forEach items="${lodingDepar ...

  7. wxpy使用

    一 简介 wxpy基于itchat,使用了 Web 微信的通讯协议,,通过大量接口优化提升了模块的易用性,并进行丰富的功能扩展.实现了微信登录.收发消息.搜索好友.数据统计等功能. 总而言之,可用来实 ...

  8. 烽火2640路由器命令行手册-13-VPDN(L2TP,PPTP,PPPOE)配置命令

    VPDN(L2TP,PPTP,PPPOE)配置命令 目  录 第1章 VPDN配置命令... 1 1.1 VPDN配置命令... 1 1.1.1 accept-dialin. 1 1.1.2 doma ...

  9. PHP微信商户支付 - 企业付款到零钱功能(即提现)技术资料汇总

    PHP实现微信开发中提现功能(企业付款到用户零钱) 一.实现该功能目的 这几天在小程序里要实现用户从系统中提现到零钱的功能,查了一下文档可以使用 企业付款到用户零钱 来实现: 官方文档:https:/ ...

  10. 利用js实现 禁用浏览器后退

    现在很多的内部系统,一些界面,都是用户手动点击退出按钮的.但是为了避免,用户误操作 点击浏览器后退,或者用鼠标手势后退什么的.容易出现误操作.        所以在有些页面上,适当的禁用浏览器的后退, ...