如何在 .NET 2.0/3.5 中将(字符串)消息从一个线程异步排队到另一个线程?
Posted
技术标签:
【中文标题】如何在 .NET 2.0/3.5 中将(字符串)消息从一个线程异步排队到另一个线程?【英文标题】:How to asynchronously queue (string) messages from one thread to another in .NET 2.0/3.5? 【发布时间】:2012-04-08 10:53:45 【问题描述】:我在Queue implementation in C# 找到了关于我想要实现的文章。但是这篇文章是基于.Net 4.0的。而 MSDN 网站只有非常简单的例子。所以决定在这里发布。
也就是说,我想通过从队列中获取字符串来实现线程在dos提示窗口中异步显示字符串。另一个线程也可能在字符串队列中异步添加额外的字符串(字符串最大条目为 20,一旦填充最大条目,不再添加)。我想根据.Net 2.0或3.5运行这个应用程序直到队列为空。(VS2008)
队列实现看起来很简单,因为.Net提供了它,但我不知道如何用这个队列实现异步部分。
谢谢。
【问题讨论】:
您可能会发现这个问题的公认答案很有趣:***.com/questions/530211/… 基于你在完成通知时所做的“异步”没有多大意义,而在非阻塞中的“异步”可能不值得复杂,所以即使阿伦的回答没有不完全按照您的要求去做,这可能是正确的方法。 【参考方案1】:所以我收集到的是,您基本上想使用 ConcurrentQueue
,但您被困在 .NET 3.5 中并且无法使用它(因为它不存在)。
这又回到了简单的操作锁定。您不希望两个线程同时访问同一个对象。
开始之前:阅读This book on C# Threading by Joseph Albahari
它涵盖了 .NET 线程,即使只是略读它也会帮助您防止遇到错误的线程错误。
您基本上需要做两件事,所以让我们分解一下:
安全访问队列
您可以使用Generic Queue<T> Class
来实现您的消息队列,但是所有更改此对象的操作都需要安全处理。
执行此操作的最简单形式是使用Lock Statement。
lock(myQueue)
myQueue.Enqueue(message);
您必须锁定所有操作,因此您需要的三个操作是 .Enqueue(...)
、.Dequeue()
和 .Count
,因为它们都访问数据。
这将防止您在将消息排队/出队时遇到多线程问题,并且生活会很好。
等待消息
要等待消息,您有多种方法可以解决此问题。其中大部分都在我上面链接的电子书中进行了概述。
最简单的是Thread.Sleep
循环
while(appIsRunning)
Thread.Sleep(100);
lock(myQueue)
while(myQueue.Count > 0)
Console.WriteLine(myQueue.Dequeue());
注意:这不是最好的方法,只是最简单的例子
这只是简单地安排这个线程在至少 100 毫秒后再次运行。 (没有保证它会从现在开始运行 100 毫秒,只是在那之前不会运行)。然后它锁定队列,因此不会发生写入,它清空队列并将行写入屏幕,然后再次循环。
如果队列是空的,它就会回到睡眠状态。
另一种解决方案是使用脉冲/等待
Monitor.Pulse
和Monitor.Wait
是一种乒乓式线程控制范例。
您可以在主线程Monitor.Wait()
中设置循环,当您将消息添加到队列时,您可以Monitor.Pulse()
将锁释放到等待线程。
这在语义上更相关,但可能效率较低,因为您的上下文切换是根据每条消息的需要进行的。
还有大约 10 种其他方法可以做到这一点,大部分都在那本书中进行了概述,但这基本上就是它的要点。
请参阅Event Signaling Section of Joseph's Book 了解所有信令方法的示例。
【讨论】:
以上是关于如何在 .NET 2.0/3.5 中将(字符串)消息从一个线程异步排队到另一个线程?的主要内容,如果未能解决你的问题,请参考以下文章
线程可以作为另一个用户执行吗? (.NET 2.0/3.5)
如何在 .NET Core 中将 JSON 序列化为没有转义字符的字符串?
如何在 .NET 中将十六进制“字符串”转换为实际的十六进制值? [复制]
如何在 .Net / C# 中将日期转换为 HTTP 格式的日期