gpt4 book ai didi

c# - C#中线程安全的可破坏事件触发类

转载 作者:太空宇宙 更新时间:2023-11-03 11:43:17 24 4
gpt4 key购买 nike

最近,我被要求实现一个类作为选择过程的一部分。我按照要求做了程序。然而,我考试失败了。我真的很想知道我的解决方案有什么问题。任何帮助深表感谢。下面给出问题和我的解决方案

问题:

实现一个线程安全类,该类从构建开始每秒触发一个事件。需要有一个函数来查找经过的秒数。此类必须实现 IDisposable,并且在调用 dispose 之后对已用秒数函数的任何调用都应该失败。

我的解决方案:

namespace TimeCounter
{
public delegate void SecondsElapsedHandler(object o, EventArgs e);
/// <summary>
/// Summary description for SecondCounter
/// </summary>
public class SecondCounter : IDisposable
{
private volatile int nSecondsElapsed;
Timer myTimer;
private readonly object EventLock = new object();
private SecondsElapsedHandler secondsHandler;
public SecondCounter()
{
nSecondsElapsed = 0;
myTimer = new Timer();
myTimer.Elapsed += new ElapsedEventHandler(OneSecondElapsed);
myTimer.Interval = 1000;
myTimer.AutoReset = false;
myTimer.Start();
}

public void OneSecondElapsed(object source, ElapsedEventArgs e)
{
try
{
SecondsElapsedHandler handlerCopy;
lock (EventLock)
{
handlerCopy = secondsHandler;
nSecondsElapsed++;

}
if (secondsHandler != null)
{
secondsHandler(this, e);
}
}
catch (Exception exp)
{
Console.WriteLine("Exception thrown from SecondCounter OneSecondElapsed " + exp.Message);
}
finally
{
if (myTimer != null)
{
myTimer.Enabled = true;
}
}
}

public event SecondsElapsedHandler AnotherSecondElapsed
{
add
{
lock (EventLock)
{
secondsHandler += value;
}
}
remove
{
lock (EventLock)
{
secondsHandler -= value;
}

}
}

public int SecondsElapsed()
{
if (this.IsDisposed)
{
throw new ObjectDisposedException("SecondCounter");
}
return nSecondsElapsed;

}

private bool IsDisposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool Disposing)
{
if (!IsDisposed)
{
if (Disposing)
{

}
if (myTimer != null)
{
myTimer.Dispose();
}

}
secondsHandler = null;
IsDisposed = true;

}
~SecondCounter()
{
Dispose(false);
}
}
}

最佳答案

有几个问题:

  1. 您可能会因为一般的异常吞噬而受到惩罚,尽管这与线程问题没有具体关系。

  2. 您的计时器存在竞争条件。Dispose,因为您可以在计时器再次设置为 Enabled 之前对其进行 Dispose,从而导致异常。

  3. 永远不要在 Dispose 中将 myTimer 设置为 null。

  4. 您正在从终结器 (disposing=false) 访问托管类 myTimer,这是个坏主意。

  5. 带锁的事件的显式实现是不必要的。委托(delegate)是不可变的,添加/删除事件永远不会导致无效的委托(delegate)状态,但如果在触发回调的同时添加/删除委托(delegate),则可能存在竞争条件。如果您在没有显式支持私有(private)委托(delegate)的情况下使用标准“公共(public)事件”声明,同步将自动处理。

  6. (要点)如果您要实现完整的 Dispose 模式,通常会将 Dispose(bool disposing) 方法标记为 protected virtual,以便派生类可以 Hook 到处置机制。更好的是,将您的类标记为密封,您就可以完全消除终结器。

关于c# - C#中线程安全的可破坏事件触发类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4081927/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com