翼度科技»论坛 编程开发 .net 查看内容

【.NET】多线程:自动重置事件与手动重置事件的区别

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
在多线程编程中,如果每个线程的运行不是完全独立的。那么,一个线程执行到某个时刻需要知道其他线程发生了什么。嗯,这就是所谓线程同步。同步事件对象(XXXEvent)有两种行为:
1、等待。线程在此时会暂停运行,等待其他线程发出信号才继续(等你约);
2、发出信号。当前线程发出信号,其他正在等待线程收到信号后继续运行(我约你)。
从前,小明、小伟、小更、小红、小黄计划到野外去烤鱼吃。但他们只确定市郊东南方向的一片区域,并不能保证具体哪个地点适合烧烤。于是,他们商量好,大家同时从家里出发。小明离那里比较近,他先去考察一下;其他人到了东南郊后集合,等小明的消息。小明考察完毕,向大家群发消息说明选定的地点是F。最后大家继续前行,奔向F。
等待事件有好几个:
1、Mutex:互斥体。一次只能有一个线程获取到互斥体,其他线程只能等。占用互斥体的线程释放后,其他线程继续抢 Mutex。然后只有一个线程能抢到,其他线程继续等……
2、AutoResetEvent:自动事件,发出信号后立刻重置。
3、ManualResetEvent:手动事件,发出信号后不会立刻重置,得手动重置。

4、CountdownEvent:这个和上面两个差不多。但它会设定一个计数,线程发出信号时会减少计数。被阻止的线程要等到计数  0)            {                // 取掉一个元素                char c = keyChars.Dequeue();                Console.WriteLine($"线程【{state}】获得字符:{c}");            }            // 解锁            Monitor.Exit(keyChars);        }    }}[/code]这里我用泛型队列 Queue 来存放键盘敲入的字符,DoSomething 方法将放入线程池中运行。在从队列中取出元素并处理时,一定要记得上锁。我用的是 Monitor 对象的静态方法来上锁和解锁,当然你可以用 lock 语句块。
  1. internal class Program
  2. {
  3.     static AutoResetEvent theEvent = new(false);
  4.     static void Main(string[] args)
  5.     {
  6.         // 启动三个线程
  7.         ThreadPool.QueueUserWorkItem(DoWorking, "A");
  8.         ThreadPool.QueueUserWorkItem(DoWorking, "B");
  9.         ThreadPool.QueueUserWorkItem(DoWorking, "C");
  10.         // 主线程监听键盘消息
  11.         while(true)
  12.         {
  13.             var keyInfo = Console.ReadKey(true);
  14.             // 看看是不是Y键
  15.             if(keyInfo.Key == ConsoleKey.Y)
  16.             {
  17.                 // 点亮信号
  18.                 theEvent.Set();
  19.             }
  20.             // 输出一行,方便判断一个循环
  21.             Console.WriteLine("------------------------------");
  22.         }
  23.     }
  24.     static void DoWorking(object? state)
  25.     {
  26.         while(true)
  27.         {
  28.             // 等待主线程的信号
  29.             // 此线程会暂停
  30.             theEvent.WaitOne();
  31.             // 得到信号了,继续运行
  32.             Console.WriteLine("{0}已收到通知", state);
  33.         }
  34.     }
  35. }
复制代码
如果不上锁,线程间在抢占资源时会导致不一致的状态。当A线程访问 keyChars.Count 属性时得到 1,还是 > 0 的,但在取出最后一个元素前,偏偏B线程动作快把最后一个元素拿走了。当A线程执行到 keyChars.Dequeue() 一句时,keyChars 队列中已经没有元素了,会发生错误。
主线程在 Enqueue 时并不需要锁定,因为元素送入队列只有一个线程在做,没人跟他抢资源,可以不锁定。
运行程序后,可以按字母、数字等按键来测试。毕竟像【F3】、【Ctrl】等按键获取到的是空白 char。

这样就顺畅很多了。
 

来源:https://www.cnblogs.com/tcjiaan/archive/2023/11/11/17826114.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具