首页 > 编程语言 >C#里有哪些线程同步的办法

C#里有哪些线程同步的办法

时间:2023-05-09 09:02:55浏览次数:51  
标签:同步 Thread C# t2 new t1 static IncrementCounter 线程

除了lock和Semaphore之外,C# 还有其他的线程同步方法,如 Monitor, Mutex, ReaderWriterLockSlim 和 ManualResetEvent等。

目录

在常见的编程语言中,同步原语可以分类为哪些?

锁Locks
信号量Semaphores
互斥量Mutexes
条件变量Condition Variables
屏障Barriers

这些同步原语在不同编程语言和操作系统中有不同的实现方式和命名,但它们的基本概念和功能是相似的。

关于锁的名词解释

放弃名词解释——看这篇文章了解锁的分类 https://juejin.cn/post/7010305230256488485

锁可重入(Reentrant)是指一个线程可以多次获得同一个锁,而不会产生死锁。当一个线程已经拥有了一个锁,再次尝试获得相同的锁时,该线程可以继续执行,而不会阻塞等待锁释放。

自旋锁(SpinLock)是一种特殊类型的锁,当一个线程试图获得已被其他线程持有的锁时,不会立即进入阻塞状态。相反,该线程会在一个循环中忙等待(busy-waiting),不断地检查锁是否可用。自旋锁是一种低级别的同步原语,通常在需要极低延迟和高性能的场景下使用。

C#里有哪些线程同步的办法

lock

优点:简单易用,适用于大多数场景,可重入。
缺点:无法手动释放锁,无法跨进程使用。

using System;
using System.Threading;

class Example
{
    private static object syncObj = new object();
    private static int counter = 0;

    static void Main()
    {
        Thread t1 = new Thread(IncrementCounter);
        Thread t2 = new Thread(IncrementCounter);

        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();

        Console.WriteLine("Counter: " + counter);
    }

    static void IncrementCounter()
    {
        for (int i = 0; i < 1000; i++)
        {
            lock (syncObj)
            {
                counter++;
            }
        }
    }
}

Semaphore

优点:可以控制同时访问资源的线程数量,可跨进程使用。
缺点:相对于lock,使用起来稍复杂。

using System;
using System.Threading;

class Example
{
    private static Semaphore sem = new Semaphore(1, 1); // Initial count: 1, Maximum count: 1
    private static int counter = 0;

    static void Main()
    {
        Thread t1 = new Thread(IncrementCounter);
        Thread t2 = new Thread(IncrementCounter);

        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();

        Console.WriteLine("Counter: " + counter);
    }

    static void IncrementCounter()
    {
        for (int i = 0; i < 1000; i++)
        {
            sem.WaitOne();
            counter++;
            sem.Release();
        }
    }
}

Monitor

优点:灵活性高,可手动控制锁的获取和释放,可重入。
缺点:使用起来较复杂,容易出错,无法跨进程使用。

using System;
using System.Threading;

class Example
{
    private static object syncObj = new object();
    private static int counter = 0;

    static void Main()
    {
        Thread t1 = new Thread(IncrementCounter);
        Thread t2 = new Thread(IncrementCounter);

        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();

        Console.WriteLine("Counter: " + counter);
    }

    static void IncrementCounter()
    {
        for (int i = 0; i < 1000; i++)
        {
            bool lockTaken = false;
            try
            {
                Monitor.Enter(syncObj, ref lockTaken);
                counter++;
            }
            finally
            {
                if (lockTaken)
                {
                    Monitor.Exit(syncObj);
                }
            }
        }
    }
}

Mutex

优点:可跨进程使用,可重入。
缺点:性能相对较差,开销较大,相对于lock和Monitor,使用起来较复杂。

using System;
using System.Threading;

class Example
{
    private static Mutex mutex = new Mutex();
    private static int counter = 0;

    static void Main()
    {
        Thread t1 = new Thread(IncrementCounter);
        Thread t2 = new Thread(IncrementCounter);

        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();

        Console.WriteLine("Counter: " + counter);
    }

    static void IncrementCounter()
    {
        for (int i = 0; i < 1000; i++)
        {
            mutex.WaitOne();
            counter++;
            mutex.ReleaseMutex();
        }
    }
}

ReaderWriterLockSlim

优点:读写锁定分离,适用于读操作远多于写操作的场景,性能较高。
缺点:使用起来相对复杂,不可跨进程使用。

using System;
using System.Threading;

class Example
{
    private static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
    private static int counter = 0;

    static void Main()
    {
        Thread t1 = new Thread(IncrementCounter);
        Thread t2 = new Thread(IncrementCounter);

        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();

        Console.WriteLine("Counter: " + counter);
    }

    static void IncrementCounter()
    {
        for (int i = 0; i < 1000; i++)
        {
            rwLock.EnterWriteLock();
            counter++;
            rwLock.ExitWriteLock();
        }
    }
}

ManualResetEvent

优点:灵活,可以用于多个线程之间的信号传递。
缺点:不是传统意义上的同步锁,只能控制线程的等待和继续,不适用于保护资源的互斥访问。

using System;
using System.Threading;

class Example
{
    private static ManualResetEvent mre = new ManualResetEvent(false);
    private static int counter = 0;

    static void Main()
    {
        Thread t1 = new Thread(IncrementCounter);
        Thread t2 = new Thread(IncrementCounter);

        t1.Start();
        t2.Start();

        mre.Set();

        t1.Join();
        t2.Join();

        Console.WriteLine("Counter: " + counter);
    }

    static void IncrementCounter()
    {
        mre.WaitOne();

        for (int i = 0; i < 1000; i++)
        {
            counter++;
        }
    }
}

请注意,这些代码示例中的同步方法各有优缺点。在实际应用中,请根据具体需求选择合适的同步方法。

在实际应用中,需要根据需求和场景来选择合适的同步方法。

  • 简单场景下,可以优先考虑使用lock。
  • 如果需要跨进程同步,可以使用Mutex或Semaphore。
  • 在读写操作不平衡的情况下,可以考虑使用ReaderWriterLockSlim。
  • 对于线程之间的信号传递,可以使用ManualResetEvent。
  • 而在需要更多控制和灵活性的场景下,可以考虑使用Monitor。

标签:同步,Thread,C#,t2,new,t1,static,IncrementCounter,线程
From: https://www.cnblogs.com/yhm138/p/17383750.html

相关文章

  • C# 窗体控件ContextMenuStrip下拉项之间的分割线
    1.效果如图: 2.选中ContextMenuStrip控件,在Items属性中添加Separator 3. (其中第3,4步,通过上下箭头,摆置好你要分割的位置)原文链接......
  • LgcHMI
    LgcHMI介绍LgcHMI是个人开发的完全免费的界面组态动态链接库,目前支持松下/基恩士PLC通信,并支持公共协议opcua/modbusTcp,各种控件满足我们正常的开发需求。使用C#编程,相对于传统组态屏可扩展性更强,如果你不会编程,它也可以拖拖控件就可以完成了组态。需要的朋友可以到nuget或www.......
  • @Accessors 注解参数
    @Accessors注解参数经常会在实体类上看到,记录一下,方便以后复习@Accessors注解的作用:当属性字段在生成getter和setter方法时,做一些相关的设置。@Accessors共有三个属性,分别是fluent,chain,prefixfluent属性不写默认为false,当该值为true时,对应字段的getter方法前面......
  • CF1825C LuoTianyi and the Show
    传送门(luogu)传送门(CF)前言我来水题解力简化题意$n$个人,$m$个座位,每个人落座的方法有三种:坐最左边的人的左边,没人的话就做$m$号座位,若最左边的为$1$号,就离开;坐最右边的人的右边,没人的话就做$1$号座位,若最右边的为$m$号,就离开;坐在$x_i$号座位上,有人就......
  • 高维数据惩罚回归方法:主成分回归PCR、岭回归、lasso、弹性网络elastic net分析基因数
    全文链接:http://tecdat.cn/?p=23378最近我们被客户要求撰写关于高维数据惩罚回归方法的研究报告,包括一些图形和统计输出。在本文中,我们将使用基因表达数据。这个数据集包含120个样本的200个基因的基因表达数据。这些数据来源于哺乳动物眼组织样本的微阵列实验1介绍在本文中,我......
  • R语言随机波动模型SV:马尔可夫蒙特卡罗法MCMC、正则化广义矩估计和准最大似然估计上证
    全文链接:http://tecdat.cn/?p=31162最近我们被客户要求撰写关于SV模型的研究报告,包括一些图形和统计输出本文做SV模型,选取马尔可夫蒙特卡罗法(MCMC)、正则化广义矩估计法和准最大似然估计法估计。模拟SV模型的估计方法:sim<-svsim(1000,mu=-9,phi=0.97,sigma=0.15)pr......
  • OpenGL学习笔记-3:编译shader报错: cannot convert from 'const highp float' to 'Frag
    报错信息: ERROR::SHADER_COMPILATION_ERRORoftype:FRAGMENTERROR:0:10:'assign':cannotconvertfrom'consthighpfloat'to'FragUserData4-componentvectorofhighpfloat'-------------------------------------------------......
  • Keycloak: Requesting Token with Password Grant
    Keycloak:RequestingTokenwithPasswordGranthttps://www.appsdeveloperblog.com/keycloak-requesting-token-with-password-grant/Inthistutorial,youwilllearnhowtouseaPasswordGrantOAuth2authorizationflowtorequestanAccessTokenandaRefre......
  • 使用Docker及安装部分软件
    一、前言最近在银行内部部署项目的时候,发现GCC版本过期,是4.5的版本,导致了Nginx和Redis都无法进行make编译安装,但是GCC版本又因为无法连接到外网,无法进行升级。那么想到了使用Docker容器化技术来进行管理。其实之前也使用过Docker,但是这次决定将其系统性的整理一下。下面章节将分......
  • StarCoder: 最先进的代码大模型
    关于BigCodeBigCode是由HuggingFace和ServiceNow共同领导的开放式科学合作项目,该项目致力于开发负责任的代码大模型。StarCoder简介StarCoder和StarCoderBase是针对代码的大语言模型(代码LLM),模型基于GitHub上的许可数据训练而得,训练数据中包括80多种编程语言......