C#中线程和定时器的使用记录

记录学习代码。

使用线程,创建一个消息队列阻塞等待消息。

使用定时器,每隔一秒钟发送一条消息。

监听键盘Esc按键实现程序退出。

代码如下:

  1 using System;
  2 using System.Collections.Concurrent;
  3 using System.Collections.Generic;
  4 using System.Linq;
  5 using System.Text;
  6 using System.Threading;
  7 using System.Threading.Tasks;
  8 
  9 namespace TimerDemo
 10 {
 11     internal class Program
 12     {
 13         public enum MessageId
 14         {
 15             None = 0,
 16             Terminate,
 17         }
 18         // 使用结构体,因为demo数据很简单
 19         public struct TaskMessage
 20         {
 21             public MessageId id;
 22             public string description;
 23             public override string ToString()
 24             {
 25                 return "ID: " + id.ToString() + ", " + description+ ")";
 26             }
 27         }
 28 
 29         private Thread threadSender;
 30         private Thread threadReceiver;
 31         private Timer timer;
 32         private volatile bool terminatable;
 33         // 使用并发安全的队列
 34         private ConcurrentQueue<TaskMessage> taskMessages;
 35         // 这里用不到太复杂的功能,所以使用轻量级信号量即可
 36         private SemaphoreSlim msgAccessableSemp;
 37 
 38         public Program()
 39         {
 40             terminatable = false;
 41             taskMessages = new ConcurrentQueue<TaskMessage>();
 42             msgAccessableSemp = new SemaphoreSlim(0, 1);
 43 
 44             threadSender = new Thread(new ThreadStart(sender));
 45             threadReceiver = new Thread(new ThreadStart(receiver));
 46             threadSender.IsBackground = true;
 47             threadReceiver.IsBackground= true;
 48             threadSender.Start();
 49             threadReceiver.Start();
 50         }
 51 
 52         public void Wait()
 53         {
 54             threadSender.Join();
 55             threadReceiver.Join();
 56         }
 57 
 58         public void PostExistRequest()
 59         {
 60             taskMessages.Enqueue(new TaskMessage { id = MessageId.Terminate, description = DateTime.Now.ToString("hh:mm:ss.fff") });
 61             msgAccessableSemp.Release();
 62         }
 63 
 64         private void sender()
 65         {
 66             // 这里的发送线程,里面可以循环干活,但是我这里没有安排其他的工作
 67             #region 创建并启动定时器
 68             timer = new Timer(new TimerCallback((obj) =>
 69             {
 70                 if (terminatable)
 71                 {
 72                     // 除非主动停止,否则这个 timer 会一直周期性运行。
 73                     timer.Dispose();
 74                     timer = null;
 75                 }
 76                 else
 77                 {
 78                     // 插入消息到队列尾部并给出一个信号量通知对方干活
 79                     taskMessages.Enqueue(new TaskMessage { id = MessageId.None, description = DateTime.Now.ToString("hh:mm:ss.fff") });
 80                     msgAccessableSemp.Release();
 81                 }
 82             }), null, 0, 1000);
 83             #endregion
 84 
 85             Console.WriteLine("消息发送线程退出!");
 86         }
 87 
 88         private void messageHandle(in TaskMessage msg)
 89         {
 90             switch (msg.id)
 91             {
 92                 case MessageId.None:
 93                     Console.WriteLine(msg.ToString());
 94                     break;
 95                 case MessageId.Terminate:
 96                     terminatable = true;
 97                     break;
 98             }
 99 
100         }
101 
102         private void receiver()
103         {
104             TaskMessage msg;
105 
106             while (!terminatable)
107             {
108                 try
109                 {
110                     // 可以无限期等待,这里为了观察特地改成600毫秒
111                     if (!msgAccessableSemp.Wait(600))
112                     {
113                         Console.WriteLine("\t无信号。");
114                     }
115 
116                     // 尝试从队列里面获取一条消息
117                     if (!taskMessages.IsEmpty && taskMessages.TryDequeue(out msg))
118                     {
119                         messageHandle(msg);
120                     }
121                     else
122                     {
123                         Console.WriteLine("\t无消息。");
124                     }
125                 }
126                 catch (Exception ex)
127                 {
128                     Console.WriteLine(ex.ToString());
129                 }
130             }
131 
132             // clear all messages.
133             int i = 0;
134             while (!taskMessages.IsEmpty)
135             {
136                 if (taskMessages.TryDequeue(out msg))
137                 {
138                     i ++;
139                     Console.WriteLine("线程结束,丢弃消息:" + msg.ToString());
140                 }
141             }
142             if (0 < i)
143             {
144                 Console.WriteLine("总计丢弃了 " + i + " 条消息。");
145             }
146             Console.WriteLine("消息接收线程退出!");
147         }
148 
149         static void Main(string[] args)
150         {
151             Console.WriteLine("启动程序");
152 
153             Program p = new Program();
154 
155             Console.WriteLine("主线程会等待全部子线程结束才会退出。");
156 
157             while (true)
158             {
159                 Console.WriteLine("你可以按Esc键结束程序。");
160                 try
161                 {
162                     ConsoleKeyInfo ki = Console.ReadKey(true);
163                     if (ki.Key == ConsoleKey.Escape)
164                     {
165                         // 发送消息结束程序
166                         p.PostExistRequest();
167                         break;
168                     }
169                 }
170                 catch (Exception ex)
171                 {
172                     Console.WriteLine("等待输入按键时检测到如下异常:");
173                     Console.WriteLine(ex.ToString());
174                 }
175             }
176 
177             p.Wait();
178             Console.WriteLine("程序结束。");
179         }
180     }
181 }

运行结果截图:

 

 《完》

posted @ 2023-01-07 12:57  -ssdq-  阅读(255)  评论(0编辑  收藏  举报