首页 > 编程语言 >C#常用的4种锁的使用以及解释

C#常用的4种锁的使用以及解释

时间:2024-07-01 14:58:59浏览次数:16  
标签:常用 种锁 C# 信号量 int static 线程 Semaphore new

1、lock

 internal class Program
    {
        static object lockObject=new object();
        static void Main(string[] args)
        {
            Student student = new Student();
            Thread thread1 = new Thread(new ThreadStart(Start1));
            thread1.Start();

            Thread thread2 = new Thread(Start2);
            thread2.Start(student);
        }

        private static void Start2(object? obj)
        {
            var student = obj as Student;
            lock (lockObject)
            {
                for (int i = 0; i < 30; i++)
                {
                    Console.WriteLine(student!.Name + i);
                }
            }
        }

        private static void Start1()
        {     
            lock (lockObject)
            {
                for (int i = 0; i < 30; i++)
                {
                    Console.WriteLine(i);
                }
            }

        }

    }

lock锁用于同步线程对共享资源的访问,这里的共享资源是静态的Console.WriteLine,当多个线程共同使用它的时候,lock内部会有一个监听器,监听它有没有在其他地方使用,有的话,我这里先暂停,它的底层是一个互斥锁,是一个非的概念。
2、Monitor

 internal class Program
    {
        static object lockObject = new object();
        static void Main(string[] args)
        {
            Student student = new Student();
            Thread thread1 = new Thread(new ThreadStart(Start1));
            thread1.Start();

            Thread thread2 = new Thread(Start2);
            thread2.Start(student);
        }

        private static void Start2(object? obj)
        {
            var student = obj as Student;
            Monitor.Enter(lockObject);         //在指定对象获取排他锁
            try
            {
                for (int i = 0; i < 30; i++)
                {
                    Console.WriteLine("张三"+i);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());

            }
            finally
            {
                Monitor.Exit(lockObject);       //释放锁
            }
        }

        private static void Start1()
        {
            for (int i = 0; i < 30; i++)
            {
                Console.WriteLine(i);
            }
        }

    }

    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public Student()
        {
            Name = "张三";
        }
    }

Monitor的底层实现同样依赖于操作系统的同步机制。在.NET中,Monitor是基于Windows操作系统的Win32 API中的WaitForSingleObject和ReleaseMutex函数实现的,或者在其他平台上使用相应的同步机制。

当调用Monitor.Enter时,如果对象的锁没有被其他线程持有,当前线程将获得锁并继续执行。如果锁已经被其他线程持有,当前线程将等待直到锁被释放。Monitor.Exit用于释放当前线程持有的锁,允许其他等待的线程尝试获取锁。

使用Monitor时,通常需要与try...finally结构一起使用,以确保即使在发生异常的情况下锁也能被正确释放。这是Monitor与lock语句的一个主要区别,因为lock语句会自动处理异常情况并释放锁。
3、Semaphore

  internal class Program
    {
        static Semaphore _semaphore;

        static int currentCount;       //当前线程信号量
       
        static RandomNumberGenerator randomNumber;
        static Random r;
        static void Main(string[] args)
        {
            r = new Random();
            randomNumber = RandomNumberGenerator.Create();
            byte[] buffer = new byte[1024];
            randomNumber.GetBytes(buffer);

          

            _semaphore =new Semaphore(1,3);
            for (int i = 0; i < 5; i++)
            {
                ThreadPool.QueueUserWorkItem(Done,i+1);
            }
            Console.ReadKey(true);
        }

        private static void Done(object? state)
        {
            int id = (int)state;
            PrintThreadStatus(id, "等待");
            _semaphore.WaitOne();
            PrintThreadStatus(id, "进入");
            PrintCount(1);
            Thread.Sleep(r.Next(1000));
            PrintThreadStatus(id, "退出");
            PrintCount(-1);
            _semaphore.Release();
        }

        //输出线程状态
        static void PrintThreadStatus(int id,string thread)
        {
            Console.WriteLine($"线程{id}:{thread}");
        }

        //修改并输出线程数量
        static void PrintCount(int add)
        {
            Interlocked.Add(ref currentCount, add);
            Console.WriteLine($"=> 信号量{Interlocked.Exchange(ref currentCount,currentCount)}");
        }
    }

锁住的对象:
在这个代码示例中,Semaphore并不是直接“锁住”某个对象,而是作为一种同步机制,用来控制同时访问某个资源(在这种情况下是临界区代码)的线程数量。Semaphore有两个重要的参数:当前信号量计数(currentCount)和最大信号量计数(maxCount)。在这个例子中,_semaphore被初始化为new Semaphore(1, 3),这意味着初始时只有一个信号量可用,但最多可以有三个线程同时持有信号量。

当一个线程调用_semaphore.WaitOne();时,如果信号量计数大于0,它将减少计数并继续执行。如果计数为0,则线程将被阻塞,直到其他线程调用_semaphore.Release();来增加信号量计数。这确保了在任何时刻,只有指定数量的线程能够进入受保护的代码区域。

使用锁(在这个例子中是Semaphore)可以使多线程按顺序执行下去,因为Semaphore限制了同时执行临界区代码的线程数量。当一个线程进入临界区并执行完毕后,它通过调用_semaphore.Release();来释放信号量,允许其他等待的线程进入。

锁的底层实现:
Semaphore的底层实现依赖于操作系统的同步机制。在.NET中,Semaphore是基于Windows API中的同步对象,如CreateSemaphore和ReleaseSemaphore,来实现的。这些API提供了一种机制,用于跨多个线程或进程同步对共享资源的访问。

当调用WaitOne方法时,如果信号量计数大于0,它会减少计数并允许线程继续执行。如果计数为0,线程将等待,直到其他线程调用Release方法来增加信号量计数。这个过程涉及到操作系统内核的调度和同步原语,如互斥锁(mutexes)、信号量(semaphores)或事件(events)。

Semaphore的实现细节可能会因操作系统而异,但其核心概念是一致的:控制对共享资源的访问,以避免竞争条件和确保数据一致性。

Semaphore用于控制对临界区的访问,确保最多只有三个线程可以同时执行Done方法中的代码。通过这种方式,Semaphore帮助维护了线程间的同步,并防止了潜在的竞态条件。
4、Mutext既然是跨进程基元同步

标签:常用,种锁,C#,信号量,int,static,线程,Semaphore,new
From: https://www.cnblogs.com/guchen33/p/18277933

相关文章

  • Docker 镜像安装
    ​​​前言Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化。在安装Docker时,我们经常需要用到镜像安装,为此我整理了一下如何通过镜像源来安装Docker的......
  • Actorcloud 开源项目分享(一) - IoT 物联网平台
    简介最近由于工作原因接触了Actorcloud这个开源项目,发现这个项目是个很不错的IoT物联网平台,值得去研究一下,但是官方的GitHub已经停止更新五六年了,重启这个项目还是挺困难的。目录简介Actorcloud项目介绍项目结构官方使用文档Actorcloud项目介绍项目地址: https......
  • LeetCode //Bash - 194. Transpose File
    194.TransposeFileGivenatextfilefile.txt,transposeitscontent.Youmayassumethateachrowhasthesamenumberofcolumns,andeachfieldisseparatedbythe’’character. Example:Iffile.txthasthefollowingcontent:nameagealice21......
  • 没有MAC电脑,如何申请苹果开发证书、上架APP Store?
    【引言】使用uni-app进行跨平台APP开发时,苹果ios平台最终还是要通过APPStore渠道发布,调试时uni-app基座也必须使用开发者证书签名后才能安装。对于使用MAC电脑的开发者,倒也不存在什么大障碍,照着文档操作就行,但是对于不使用MAC电脑,身边也没有MAC电脑,采购预算又紧张的开发者和团......
  • 在React项目中使用iframe嵌入一个网站
    在React项目中使用iframe嵌入一个网站非常简单。以下是如何在页面中嵌入百度网站的步骤:1.创建一个新的组件用于嵌入iframe首先,在src/components文件夹中创建一个新的文件Baidu.js。在Baidu.js文件中,编写如下代码://src/components/Baidu.jsimportReactfrom'react'......
  • clickhouse集群及单节点库表占用存储
    1、单节点查询库表存储占用‘system’:库名SELECT  databaseAS`库名`,  tableAS`表名`,  sum(rows)AS`总行数`,  formatReadableSize(sum(data_uncompressed_bytes))AS`原始大小`,  formatReadableSize(sum(data_compressed_bytes))AS`压......
  • DWA(Dynamic Window Approach)局部路径规划算法详解及代码实现
    DWA(Dynamic Window Approach)局部路径规划算法详解及代码实现二、算法原理一句话概况,就是假定机器人当前以若干组容许范围内的速度(差速轮为例:线速度V,角速度W)进行移动,并对这若干组速度进行轨迹计算,得到若干组轨迹,再根据若干条评分机制选择最好的轨迹所对应的速度作为dwa输......
  • 【机器学习】语音转文字 - FunASR 的应用与实践(speech to text)
    本文将介绍FunASR,一个多功能语音识别模型,包括其特点、使用方法以及在实际应用中的表现。我们将通过一个简单的示例来展示如何使用FunASR将语音转换为文字,并探讨其在语音识别领域的应用前景。一、引言随着人工智能技术的不断发展,语音识别技术在各个领域得到了广泛应用。......
  • PagePlug企业版案例(二)—表单生成Excel文件并发送至邮箱中
    一、背景PagePlug是appsmith中国化项目,一款面向研发开发使用、开源的、前后端一体的低代码工具,拥有强大的可视化建模、数据库和API集成能力,目前已有将近超千家企业将PagePlug低代码开发工具融入内部研发体系,相较于传统的产研开发,使用PagePlug可大幅提升研发效率,节省项目迭代维......
  • GEE问题:Landsat Collection 2不同传感器之间是否需要进行协调校正?
    LandsatTeam团队和GEE团队对于大多数应用而言,在使用采集2地表反射率产品时,无需进行任何传感器间协调校正(转述Landsat科学团队MikeWulder的信息)(个人经验)。使用波段比指数时尤其如此。您提到的Roy等人的系数是为采集前数据开发的。大地遥感卫星档案现已进入第2个数......