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 }
运行结果截图:
《完》
如果转载,请注明出处。https://www.cnblogs.com/ssdq/