上一篇文章主要带领大家认识了线程,也了解到了线程的基本用法和状态,接下来就让我们一起学习下什么是线程同步。

线程中异常的处理

在线程中始终使用try/catch代码块是非常重要的,因为不可能在线程代码之外来捕获到异常。

可以阅读下面的代码,这块是做的验证,证明在线程之外捕获异常是错误的选择,应该在线程中时时刻刻都使用异常处理机制。

        static void Main(string[] args)
{
Thread twoThread = new Thread(TwoMethod);
twoThread.Start();
twoThread.Join();
try
{
Thread oneThread = new Thread(OneMethod);
oneThread.Start();
}
catch (Exception ex)
{
Console.WriteLine("外部捕获线程one的异常:"+ex.Message);
}
Console.ReadKey();
} static void OneMethod()
{
Console.WriteLine("Start OneMethod");
Thread.Sleep(TimeSpan.FromSeconds(2));
throw new Exception("异常01");
} static void TwoMethod()
{
try
{
Console.WriteLine("Start TwoMethod");
Thread.Sleep(TimeSpan.FromSeconds(1));
throw new Exception("异常02");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

下面图片是输出报错的结果,可以看到OneThread的异常没有被外部的try/catch捕获到,导致直接在线程内部提示错误,导致程序崩溃。

看到这个情况,那么我们在以后使用线程的时候,就需要特别的注意,一定要在线程中进行异常的处理和捕获,千万别遗留任何未处理的异常,因为如果线程中有未被处理的异常会导致整个程序都会受到影响,可能导致整个软件崩溃。

线程同步

在上一篇推文中,我们了解到了Lock加锁的机制,它是可以保证将某个变量或者某个模块锁住,当出现多个线程同时访问时锁就会起作用,只允许一个线程访问,其余的等待,其访问完后其余的才可以进行访问。但是这种机制有一定的局限性,在多核CPU设备中,让其余线程等待是极大浪费资源的,而且这种解决办法会导致死锁的现象。

上面说的也就是所谓的竞争条件问题的解决方法,导致这个问题的原因是多线程的执行并没有正确同步。当一个线程执行递增和递减操作时,其他线程需要依次等待。这种常见问题通常被称为线程同步。这种问题出现在当线程中有共享资源或者对象时,才会进行线程同步,如果无共享对象,则无需进行线程同步。

当在线程中有共享资源时,可使用下面的两种方式进行处理。

一、原子操作

来实现对共享资源的访问。其实就是一个操作只占用一个量子的时间,一次就可以完成。也就是说只有当前操作完成后,其他线程才能执行其他操作。这样就避免了使用锁,排除了死锁的情况。

原子操作就是使用C#系统自带的Interlocked类来对线程不安全的对象进行处理,借助Interlocked类,无需锁定任何对象即可获取到正确的结果,Interlocked类提供Increment,Decrement和Add等基本数学操作的原子方法,从而可以帮助我们无需使用锁,避免出现各种死锁问题。

    /// <summary>
/// 线程不安全
/// </summary>
class Counter
{
private int _count;
public int Count { get { return _count; } }
public void Add()
{
_count++;
}
public void Delete()
{
_count--;
}
}
    /// <summary>
/// 不加锁 ,但线程是安全的。
/// 可避免在线程中出现死锁
/// </summary>
class CounterNoLock
{
private int _count;
public int Count { get { return _count; } }
public void Add()
{
Interlocked.Increment(ref _count); //递增
}
public void Delete()
{
Interlocked.Decrement(ref _count); //递减
}
}

二、将等待的线程置于阻塞状态

这个处理方法是在第一个原子操作无效切程序的逻辑更加复杂的情况下才使用的,用于协调线程。

当线程处理阻塞状态时,只会占用尽可能少的CPU时间,这就意味着将引入至少一次所谓的上下文切换

上下文切换:指操作系统的线程调度器,该调度器会保持等待的线程的状态,并切换到另一个线程,依次恢复等待的线程状态。虽然会消耗极大的资源,但是如果线程被挂起很长时间这么做是值得的。这种也就内核模式,因为只有操作系统的内核才能阻止线程使用CPU时间。

用户模式: 如果线程只是等候一小会,那最好只是简单的等待,而不用将线程切换到阻塞状态。还有一种为混合模式,也就是先尝试使用用户模式,如果线程等候时间过长,则会切换到阻塞状态以节省CPU资源。

下面的DEMO主要介绍SemaphoreSlim类,该类用于限制了同时访问同一个资源的线程数量。

        static void Main(string[] args)
{
for (int i = 1; i <=6; i++)
{
string threadName = "Thread " + i;
int secondsWait = 2;
var thread = new Thread(( )=>DataConnect(threadName,secondsWait));
thread.Start();
}
Console.ReadKey();
} static SemaphoreSlim _semaphore = new SemaphoreSlim(4); //默认4个线程可同时访问 static void DataConnect(string name,int seconds)
{
Console.WriteLine("wait 线程的名字:",name);
_semaphore.Wait();
Console.WriteLine("Connect 线程的名字:" + name);
Thread.Sleep(TimeSpan.FromSeconds(seconds));
_semaphore.Release();
}

上面的代码利用SemaphoreSlim类,设置其构造函数为4,也就是其指定允许的并发线程数量。上面使用信号系统限制了访问数据连接的并发数为4个,当有4个线程进行访问时,其他两个线程需要等待,知道之前线程中某一个完成工作并调用Relece方法来发出信号。

小寄语

人生短暂,我不想去追求自己看不见的,我只想抓住我能看的见的。

原创不易,给个关注。

我是阿辉,感谢您的阅读,如果对你有帮助,麻烦点赞、转发 谢谢。

C#多线程开发-线程同步 02的更多相关文章

  1. C#多线程之线程同步篇3

    在上一篇C#多线程之线程同步篇2中,我们主要学习了AutoResetEvent构造.ManualResetEventSlim构造和CountdownEvent构造,在这一篇中,我们将学习Barrier ...

  2. C#多线程之线程同步篇2

    在上一篇C#多线程之线程同步篇1中,我们主要学习了执行基本的原子操作.使用Mutex构造以及SemaphoreSlim构造,在这一篇中我们主要学习如何使用AutoResetEvent构造.Manual ...

  3. C#多线程之线程同步篇1

    在多线程(线程同步)中,我们将学习多线程中操作共享资源的技术,学习到的知识点如下所示: 执行基本的原子操作 使用Mutex构造 使用SemaphoreSlim构造 使用AutoResetEvent构造 ...

  4. 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock

    [源码下载] 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLoc ...

  5. 重新想象 Windows 8 Store Apps (47) - 多线程之线程同步: Semaphore, CountdownEvent, Barrier, ManualResetEvent, AutoResetEvent

    [源码下载] 重新想象 Windows 8 Store Apps (47) - 多线程之线程同步: Semaphore, CountdownEvent, Barrier, ManualResetEve ...

  6. IOS 多线程,线程同步的三种方式

    本文主要是讲述 IOS 多线程,线程同步的三种方式,更多IOS技术知识,请登陆疯狂软件教育官网. 一般情况下我们使用线程,在多个线程共同访问同一块资源.为保护线程资源的安全和线程访问的正确性. 在IO ...

  7. 关于Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇高质量的博文)

    Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇质量高的博文) 前言:在学习多线程时,遇到了一些问题,这里我将这些问题都分享出来,同时也分享了几篇其他博客主的博客,并且将我个人的理解也分享 ...

  8. Java:多线程,线程同步,同步锁(Lock)的使用(ReentrantLock、ReentrantReadWriteLock)

    关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨Lock对象. synchronize ...

  9. MFC——9.多线程与线程同步

    Lesson9:多线程与线程同步 程序.进程和线程是操作系统的重点,在计算机编程中.多线程技术是提高程序性能的重要手段. 本文主要解说操作系统中程序.进程和线程之间的关系,并通过相互排斥对象和事件对象 ...

随机推荐

  1. js中==和===的区别以及总结

    js中==和===的区别以及总结 学习js时我们会遇到 == 和 === 两种符号,现做总结如下 两种符号的定义 "==" 叫做相等运算符 "===" 叫做严格 ...

  2. shell脚本(12)-特殊变量介绍

    一.特殊变量介绍: 1.$* :代表所有参数,其间隔为IFS内参数的第一个字元 2.$@ :与*星号类同,不同之处在于不参照IFS 3.$# :代表参数数量 4.$: 代表上一个指令的返回值 5.$- ...

  3. SQL之case when then用法_之二

    select CustomerNo, Name, Sex, Birthday, IDType, IDNo, validityday, case (null ) when '1' then '高级VIP ...

  4. 初学MyBatis(踩坑)Error querying database. Cause: java.sql.SQLException: java.lang.ClassCastException: java.math.BigInteger cannot be cast to java.lang.Long

    最近在学习Mybatis,代码全部根据教程写好了,一运行结果报了一个错误,主要错误内容: Caused by: org.apache.ibatis.exceptions.PersistenceExce ...

  5. 添加数据时报错:An error occurred while updating the entries. See the inner exception for detail。

    场景:前几天在项目开发时,有个bug经常出现,今天花了一整天,终于把它解决了.记录一下解决流程. 解决方法: 主要报错的地方在添加的部分: 1 foreach (var requestProperty ...

  6. 🔥 LeetCode 热题 HOT 100(71-80)

    253. 会议室 II(NO) 279. 完全平方数 class Solution { public int numSquares(int n) { // dp[i] : 组成和为 i 的最少完全平方 ...

  7. 论文笔记:(NIPS2018)PointCNN: Convolution On X-Transformed Points

    目录 摘要 一.2D卷积应用在点云上存在的问题 二.解决的方法 2.1 idea 2.2 X-conv算子 2.3 分层卷积 三.实验 3.1分类和分割 3.2消融实验.可视化和模型复杂度 总结 仍存 ...

  8. Windows系统安装Mariadb数据库(zip包方式安装)--九五小庞

    1.去Mariadb官网下载zip安装包 下载地址:https://downloads.mariadb.org/mariadb/10.3.31/ 2.解压压缩包到指定的安装位置 3.在安装包的data ...

  9. Nature | 多层次蛋白质组学综合分析冠状病毒侵染宿主细胞的分子机制

    冠状病毒是一种自然界普遍存在的单股正链RNA病毒,电镜下呈日冕状或皇冠状,故命名为冠状病毒.在本世纪初短短20年中,共爆发了三次冠状病毒疫情,即2003年SARS-CoV.2012年MERS-CoV和 ...

  10. 面试官:MySQL 有哪些锁??

    大家好,我是小林. 这次,来说说 MySQL 的锁,主要是 Q&A 的形式,看起来会比较轻松. 不多 BB 了,发车! 在 MySQL 里,根据加锁的范围,可以分为全局锁.表级锁和行锁三类. ...