- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在为我们正在运行的 ASP.NET 应用程序编写我们自己的记录器。在当前的代码库中,我们似乎遇到了线程问题,我正在尝试逐个组件地消除以找出导致此问题的原因。症状是应用程序启动后网络服务器上的 CPU 达到 100%。
我要删除的第一件事是我编写的记录器,因为它是代码库中最新添加的内容之一。记录器背后的想法如下:
可以从任何地方调用静态类,并且 XmlLogger 有一个后台线程从 MessageQueue 获取消息并处理它。所以我需要使对该队列的访问是线程安全的。 MessageQueue 类的代码如下所示:
public sealed class MessageQueue
{
#region Private Fields
private readonly Queue<IMessage> _messageQueue;
#endregion
#region Constructor
/// <summary>
/// <para>Creates a new instance of the class and initializes all internal fields.</para>
/// </summary>
public MessageQueue()
{
_messageQueue = new Queue<IMessage>();
}
#endregion
#region Properties
/// <summary>
/// <para>Gets the number of <see cref="IMessage"/> objects in the queue.</para>
/// </summary>
public int NumberOfMessage
{
get
{
lock(_messageQueue)
{
return _messageQueue.Count;
}
}
}
#endregion
#region Public Members
/// <summary>
/// <para>Adds a new <see cref="IMessage"/> to the bottom of the queue.</para>
/// </summary>
/// <param name="message">The <see cref="IMessage"/> to be added to the queue.</param>
public void AddMessage(IMessage message)
{
lock(_messageQueue)
{
_messageQueue.Enqueue(message);
Monitor.PulseAll(_messageQueue);
}
}
/// <summary>
/// <para>Gets the first <see cref="IMessage"/> from the queue.</para>
/// </summary>
/// <returns>The first <see cref="IMessage"/> from the queue.</returns>
public IMessage GetMessage()
{
lock(_messageQueue)
{
while (_messageQueue.Count == 0) Monitor.Wait(_messageQueue);
return _messageQueue.Dequeue();
}
}
#endregion
}
向任何记录器的 MessageQueue 添加消息的代码如下所示:
/// <summary>
/// <para>Logs a specified <see cref="IMessage"/> in the various loggers.</para>
/// </summary>
/// <param name="message">The <see cref="IMessage"/> to be logged.</param>
public void LogMessage(IMessage message)
{
lock(_loggerLock)
{
foreach (AbstractLogger logger in _loggers)
logger.MessageQueue.AddMessage(message);
}
}
我已经锁定了 LogManager,因为消息的插件不应与从队列中添加/删除记录器冲突。我确定这里不存在问题。下面的代码显示了包含 MessageQueue 对象的 XmlLogger 的处理例程。
private void ProcessMessage()
{
// This thread should be running indefinitly untill the abort is called.
while (true)
{
try
{
// Get the first message available from the Queue
IMessage message = MessageQueue.GetMessage();
// If we could retrieve a valid message, process it.
if (message != null && (LogSettings.Level & message.Level) == message.Level)
{
// Determine the path to the logfile
string logpath = DetermineFilePath(message.Context);
// Write the message into the file.
WriteMessage(logpath, message);
}
}
catch(ThreadAbortException)
{
break;
}
catch (Exception ex)
{
Debug.WriteLine(string.Format("InnerException caught: '{0}'", ex.Message));
}
finally
{
Thread.Sleep(100);
}
}
}
我想知道的是,这段代码是使用 Monitor.Pulse 和 Monitor.Wait 例程的正确方法吗?如果不是,我应该更改什么以防止出现问题?
编辑:请不要就使用现有记录器提出问题/讨论。这不是一个选择
EDIT2:从 anwser 运行该工具,这是输出:
------------------------------------ 5956 Kernel: 0 User: 156250 TenForce.Execution.Logging.Loggers.XmlLogger.ProcessMessage System.Threading.ExecutionContext.Run System.Threading.ExecutionContext.Run System.Threading.ThreadHelper.ThreadStart Other Stacks:
TenForce.Execution.Logging.Loggers.XmlLogger.ProcessMessage System.Threading.ExecutionContext.Run System.Threading.ExecutionContext.Run System.Threading.ThreadHelper.ThreadStart
对我来说听起来有点太高了......
最佳答案
是的,看起来不错;您的出队正确地进行了检查/循环(并且没有假设脉冲意味着现在有数据,这可能会导致异常),所以大部分时间应该是空闲的。你的入队是相似的。也许我会补充:如果您添加了第一项,则仅脉冲:
lock(_messageQueue)
{
_messageQueue.Enqueue(message);
if(_messageQueue.Count == 1) Monitor.PulseAll(_messageQueue);
}
(否则,您的读者不会等待)
要调查高 CPU,请使用 CPU 分析器 - 猜测通常不是一个好的方法。山姆藏红花 has one here我们使用的;它可以在生产网络服务器上使用(只是......不是所有的时间!)
关于c# - Monitor.PulseAll 的正确用法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8307318/
我正在为我们正在运行的 ASP.NET 应用程序编写我们自己的记录器。在当前的代码库中,我们似乎遇到了线程问题,我正在尝试逐个组件地消除以找出导致此问题的原因。症状是应用程序启动后网络服务器上的 CP
任何人都可以用简单的例子来解释我如何处理 Monitor.PulseAll()。我已经从这个 stackoverflow 中找到了一些例子。因为我是初学者,我觉得这些超出了我的理解范围。 最佳答案 怎
我有一种情况,有时休眠线程不会被 Monitor.PulseAll(object lock) 命令唤醒。这种现象不是确定性的。通常它可以工作,但有时在调试期间,休眠线程无法唤醒并且我的队列不断填满
我很难理解 Wait()、Pulse()、PulseAll()。他们都能避免僵局吗?如果您解释一下如何使用它们,我将不胜感激? 最佳答案 简短版: lock(obj) {...} 是 Monitor.
Delphi Docwiki 解释说 Pulse通知等待队列中的下一个线程,一旦调用线程释放该对象,它将能够锁定指定的对象。 PulseAll向等待队列中的所有线程发出信号。 我found这段代码在线
在有多个“请求线程”和一个哑“工作线程”的情况下,请求线程必须排队。 考虑两种可能性: 每个请求线程在其自己的专用 对象上调用 Monitor.Wait,该对象进入 FIFO 队列。当结果到达时,最旧
我是 CSharp 和线程的新手。 为了熟悉Monitor.Wait、Monitor.lock和Monitor.PulseAll,我构建了一个场景描述如下。 “一个 FootballGround 由不
Monitor.PulseAll 通知队列中的所有等待线程。 Monitor.Pulse 通知等待队列中的一个线程。 (下一个等待线程) 只有下一个线程(一个线程)才能获取锁。那有什么区别呢? 什么时
是否有 .Net 类可以执行 ManualResetEvent.PulseAll() 会执行的操作(如果存在)? 我需要自动释放一组等待同一信号的线程。 (对于我的预期用途,我并不担心“线程踩踏”。)
在使用 Monitor.PulseAll() 进行线程同步的库中,我注意到从调用 PulseAll(...) 到线程被唤醒的延迟似乎遵循“阶梯”分布 - - 步幅极大。被唤醒的线程几乎没有做任何工作;
我是一名优秀的程序员,十分优秀!