线程通信——信号量与读写锁

3.信号量(Semaphore):控制同时访问共享资源的最大线程数。

3.1介绍

信号量是一种同步机制,可以控制同时访问共享资源的最大线程数。它通过维护一个计数器实现,信号量的计数器最大数代表可同时访问共享资源的线程数,线程调用WaitOne() 方法时,如果信号量计数器大于0,则计数器减1,并允许线程继续执行;若计数器为0,则线程被阻塞并等待其他线程释放信号量。通过调用 Release() 方法,可以增加信号量的计数值,从而允许一个或多个等待中的线程获取信号量并继续执行。

3.2应用

//用信号量限制
 #region 信号量的使用
 // 创建一个信号量,最大容量为3
 private static Semaphore _semaphore = new Semaphore(3, 3);//param1 初始值 param2 最大值
 private static void TestSemaphore()
 {
     for (int i = 0; i < 10; i++)
     {
         Thread t = new Thread(new ParameterizedThreadStart(ProcessSemaphore));
         t.Start(i);
     }
     Console.ReadKey();
 }
 private static void ProcessSemaphore(object threadId)
 {
     Console.WriteLine($"任务 {threadId} 正在等待信号量...");
     // 请求信号量
     _semaphore.WaitOne();
     try
     {
         Console.WriteLine($"任务 {threadId} 获取了信号量,正在访问资源...");
         for (int i = 0; i < 10; i++)
         {
             Console.WriteLine($"任务 {threadId} 正在执行第 {i} 次操作...");
             Thread.Sleep(100);
         }
     }
     finally
     {
         // 释放信号量
         _semaphore.Release();
         Console.WriteLine($"任务 {threadId} 释放了信号量");
     }
 }
 #endregion

 

4.读写锁(ReaderWriterLockSlim):学习如何在读多写少的情况下提高并发性能。

4.1介绍

在 C# 中,ReaderWriterLockSlim 是一种用于控制对共享资源的并发访问的锁,适用于读多写少的场景。与普通的锁相比,ReaderWriterLockSlim 允许多个线程同时读取共享资源,但在写入时会阻止其他读写操作,从而实现更高的并发性能。

4.2与普通锁对比

 #region 普通锁实现竞争资源读写 读多写少
 private static int _resource = 0;
 private static readonly object _lockResource = new object();
 private static long TestLockResource()
 {
     List<Thread> threads = new List<Thread>();
     //记录开始时间
     Stopwatch stopwatch = Stopwatch.StartNew();
     //开启20个读线程
     for (int i = 0; i < 20; i++)
     {
         var t = new Thread(ReadResource);
         t.Start();
         threads.Add(t);
     }
     //开启2个写线程 100ms写一个数据 写1-100
     for (int i = 0; i < 2; i++)
     {
         var t = new Thread(new ParameterizedThreadStart(WriteResource));
         t.Start(t.ManagedThreadId);
         threads.Add(t);
     }
     //等待所有线程结束
     threads.ForEach(t => t.Join());
     //记录结束时间
     stopwatch.Stop();
     Console.WriteLine($"应用普通总共耗时:{stopwatch.ElapsedMilliseconds} ms.");
     return stopwatch.ElapsedMilliseconds;
 }
 private static void ReadResource()
 {
     lock (_lockResource)
     {
         for (int i = 0; i < 100; i++)
         {
             Console.WriteLine($"当前资源值为:{_resource} 读取次数:{i}");
             Thread.Sleep(10);
         }
     }
 }
 private static void WriteResource(object tid)
 {
     for (int i = 0; i < 100; i++)
     {
         Console.WriteLine($"线程{tid}正在写入资源... 次数:{i}");
         lock (_lockResource)
         {
             _resource = i;
             Console.WriteLine($"当前资源值为:{_resource}");
         }
         Thread.Sleep(10);
     }
 }
 #endregion

 缺点:使用普通锁时,读得时候也要阻塞线程,而使用读写锁可以在当前线程没有写得情况下,读线程可以多个同时读,用法如下:

#region 使用读写锁实现资源读写
 private static int _resource2 = 0;
 private static readonly ReaderWriterLockSlim _lockResource2 = new ReaderWriterLockSlim();
 private static long TestLockResource2()
 {
     List<Thread> threads = new List<Thread>();
     //记录开始时间
     Stopwatch stopwatch = Stopwatch.StartNew();
     //开启20个读线程
     for (int i = 0; i < 20; i++)
     {
         var t = new Thread(ReadResource2);
         t.Start();
         threads.Add(t);
     }
     //开启2个写线程 100ms写一个数据 写1-100
     for (int i = 0; i < 2; i++)
     {
         var t = new Thread(new ParameterizedThreadStart(WriteResource2));
         t.Start(t.ManagedThreadId);
         threads.Add(t);
     }
     //等待所有线程结束
     threads.ForEach(t => t.Join());
     //记录结束时间
     stopwatch.Stop();
     Console.WriteLine($"读写锁总共耗时:{stopwatch.ElapsedMilliseconds} ms.");
     return stopwatch.ElapsedMilliseconds;
 }
 private static void ReadResource2()
 {
     _lockResource2.EnterReadLock();
     try
     {
         for (int i = 0; i < 100; i++)
         {
             Console.WriteLine($"当前资源值为:{_resource2} 读取次数:{i}");
             Thread.Sleep(10);
         }
     }
     finally
     {
         _lockResource2.ExitReadLock();
     }
 }
 private static void WriteResource2(object tId)
 {
     for (int i = 0; i < 100; i++)
     {
         Console.WriteLine($"线程{tId}正在写入资源... 次数:{i}");
         _lockResource2.EnterWriteLock();
         try
         {
             _resource2 = i;
             Console.WriteLine($"当前资源值为:{_resource2}");
             Thread.Sleep(10);
         }
         finally
         {
             _lockResource2.ExitWriteLock();
         }
     }
 }
 #endregion

结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值