基本概念
什么是线程
线程是操作系统中能够独立运行的最小单位,也是程序中能够并发执行的一段指令序列。
线程是进程的一部分,一个进程可以包含多个线程,这些线程共享进程的资源。
进程有入口线程,也可以创建更多的线程
为什么要多线程
批量重复任务希望同时进行(比如对数组中的每个元素都进行相同且耗时的操作)
多个不同任务希望同时进行,互不干扰(比如有多个后台线程需要做轮询等操作)
什么是线程池
一组预先创建的线程,可以被重复使用来执行多个任务。
避免频繁地创建和销毁线程,从而减少了线程创建和销毁的开销,提高了系统的性能和频率。
异步编程默认使用线程池。
什么是线程安全
线程安全
多个线程访问共享资源时,对共享资源的访问不会导致数据不一致或不可预期的结果
同步机制
用于协调和控制多个线程之间执行顺序和互斥访问共享资源
确保线程按照特定的顺序执行,避免竞态条件和数据不一致的问题
原子操作
在执行过程中不会被中断的操作。不可分割,要么完全执行,要么完全不执行,没有中间态。
在多线程环境下,原子操作能够保证数据的一致性和可靠性,避免出现竞态条件和数据竞争的问题
常用实现方法
线程、线程池、异步编程、考虑自带方法
自带方法
Parallel----For、ForEach、Invoke
PLINQ----AsParallel、AsSequential、AsOrdered
线程
线程的创建
创建Thread实例,并传入ThreadStart委托----还可以配置线程,如是否为后台线程
调用Thread.Start方法,还可以传参
线程的终止
调用Thread.Join方法,等待线程的结束
调用Thread.Interrupt方法,中断线程的执行
不能调用abort?
使用Abort方法来强制终止线程可能导致一些严重的问题,包括资源泄露和不可预测的行为
较新版本的.net中如果使用这个方法,会包PlatformNotSupportedException
推荐使用Thread.Interrupt或CancellationToken
线程的挂起与恢复
Thread.Suspend以及Thread.Tesume,在较新版本的.NET中,这两个方法已经被标记为Obsolete,且调用会报错,推荐使用锁,信号量等方式实现这一逻辑
线程安全与同步机制
原子操作,锁与信号量,轻量型,不要自己造轮子
为什么要线程同步?
进程同步(Process Synchronization)是指协调多个并发运行的进程,让它们按照预定的规则访问共享资源或执行操作.
多个线程同时使用共享对象会造成很多问题,同步这些线程使得对共享对象的操作能够以正确的顺序执行是非常重要的。
互斥量(Mutex)的核心概念
斥量(Mutex,全称 Mutual Exclusion)是 C# 中用于进程间或线程间同步 的核心机制,本质是一个 "互斥锁"------ 它保证在同一时间,只有一个线程 / 进程能获取到这个锁并执行临界区代码,其他线程 / 进程必须等待,直到锁被释放。
和 C# 中另一个常用的锁(lock关键字)相比,Mutex 的核心区别是:
| 特性 | lock(监视器) |
Mutex(互斥量) |
|---|---|---|
| 作用范围 | 仅当前进程内的线程 | 跨进程 + 进程内线程 |
| 所有权 | 属于获取锁的线程 | 属于获取锁的线程 |
| 系统资源 | 轻量级(托管资源) | 重量级(系统内核对象) |
| 跨进程支持 | 不支持 | 支持(通过命名 Mutex) |
信号量(Semaphore)的核心概念
信号量是一种控制并发访问数量 的同步机制,核心作用是限制同时访问某一共享资源的线程 / 进程数量(而 Mutex/lock 是限制 "只能 1 个")。
| 特性 | lock(监视器) | Mutex(互斥量) | Semaphore/SemaphoreSlim |
|---|---|---|---|
| 并发数限制 | 固定 1 个 | 固定 1 个 | 自定义 N 个(如 2/3/5 个) |
| 作用范围 | 仅进程内线程 | 跨进程 + 进程内线程 | Semaphore 跨进程,SemaphoreSlim 仅进程内 |
| 系统资源量级 | 最轻量(托管资源) | 重量级(内核对象) | Semaphore 重量级,SemaphoreSlim 轻量级 |
| 异步支持 | 无 | 无 | SemaphoreSlim 支持WaitAsync()(异步等待) |
| 典型场景 | 进程内单线程访问 | 跨进程单实例 / 互斥 | 限流(如同时 3 个线程处理任务)、连接池 |