C# 定时器和线程安全
我有一个带有对象数组的 C# 类,每个对象代表与外部设备的打开连接。默认情况下,连接在 n 个空闲时间后超时,我想避免这种情况。我计划使用一个每 n-2 个空闲小时触发一次的计时器,并通过一个回调调用一个方法来触摸每个对象并有效地重置超时。
该类需要在 Windows 窗体和非基于窗体的项目中可用,因此我正在考虑使用 System.Timers.Timer 和一个锁来限制任何其他线程在超时重置期间访问该数组。
使用计时器会带来线程安全隐患,例如,如果在计时器回调确定对象存在和重置其超时之间破坏其中一个对象,则会尝试读取未初始化的内存。但是,我的问题是在类中的多个位置访问该数组。在计时器回调正在进行时,锁应该阻止对数组的所有访问,如下所示:
class MyClass
{
private System.Timers.Timer timer;
private object locker = new object();
public void Run()
{
timer = new System.Timers.Timer();
timer.Interval = 21600000; //6 hours
timer.Elapsed += AccessArrayCallback;
timer.Start();
}
public void AccessArrayCallback(object sender, EventArgs e)
{
timer.Enabled = false;
lock (locker)
{
/*
if (called by timer)
{
iterate through array and reset connections;
}
else
{
Call appropriate function that reads/writes array using EventArgs delegate
}
*/
}
timer.Enabled = true;
}
}
在继续使用此方法之前有几个问题:
是否有针对此类问题的既定模式/更优雅的方法?
在 EventArgs 中使用委托是否正确?类中需要访问数组的任何其他方法都将调用回调并相应地填充 EventArgs。
提前致谢。
I have a C# class with an array of objects, each object representing an open connection to an external device. The connections time out by default after n idle hours which I want to avoid. I plan to make use of a timer that trips every n-2 idle hours, with a callback that invokes a method to touch each object and effectively reset the timeout.
The class needs to be usable in both Windows forms and non forms-based projects, hence I am considering using System.Timers.Timer and a lock to restrict any other thread from accessing the array during timeout reset.
Using a timer introduces thread safety implications, e.g. if one of the objects is destructed in between the timer callback determining that an object exists and resetting its timeout, there will be an attempt to read uninitialised memory. However, my problem is that the array is accessed in a number of places in the class. The lock should prevent all access to the array while the timer callback is in progress as follows:
class MyClass
{
private System.Timers.Timer timer;
private object locker = new object();
public void Run()
{
timer = new System.Timers.Timer();
timer.Interval = 21600000; //6 hours
timer.Elapsed += AccessArrayCallback;
timer.Start();
}
public void AccessArrayCallback(object sender, EventArgs e)
{
timer.Enabled = false;
lock (locker)
{
/*
if (called by timer)
{
iterate through array and reset connections;
}
else
{
Call appropriate function that reads/writes array using EventArgs delegate
}
*/
}
timer.Enabled = true;
}
}
A few questions before I continue with this approach:
Is there an established pattern/more elegant approach to this kind of problem?
Is it correct to use a delegate in EventArgs? Any other method in the class requiring access to the array will call the callback and populate EventArgs appropriately.
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
由于锁是私有对象,系统的其他部分将无法访问它以达到您所需的线程安全级别。这就是创建 Concurrent Bag 及其朋友的原因。代表部分如果没问题的话。
Since the lock is a private object, the other part of the system won't be able to access it to acheive your desired level of thread saftey. This is why Concurrent Bag and it's friends were created. The delegate part if fine though.