Windows 服务中的 Timer Elapsed 事件一一
Timer Elapsed event one by one in Windows Service
我用 C# 创建了 windows 服务。我使用 timer elapsed 方法对数据库执行一些 CRUD 操作。例如
tmrAPACSEvent = new Timer(10000);
tmrAPACSEvent.Elapsed += new ElapsedEventHandler(tmrAPACSEvent_Elapsed);
tmrAPACSEvent.Enabled = true;
我在 OnStart 方法中创建了这个计时器,事件是
private void tmrAPACSEvent_Elapsed(object sender, ElapsedEventArgs e)
{
Library.WriteErrorLog("tmrAPACSEvent ticked and some job has been done successfully");
try
{
var UnProcessedEvents = BLCustomService.GetCustomEvents();
if (UnProcessedEvents != null)
{
foreach (EventData eventData in UnProcessedEvents)
{
Library.WriteErrorLog(BLCustomService.ChangeEventStatus(eventData).ToString());
Library.WriteErrorLog(eventData.EventId.ToString());
var ed = new EventData()
{
dtRealDateTime = eventData.dtRealDateTime,
dwCardNumber = eventData.dwCardNumber,
strHolderName = eventData.strHolderName,
strInitObjName = eventData.strInitObjName
};
ed = BLCustomService.AddEvent(ed);
}
Library.WriteErrorLog("Events added");
}
}
catch (Exception exception)
{
Library.WriteErrorLog("Error 96: " + exception.StackTrace);
}
}
当我启动服务时,事件并行进行,并且我在数据库中获得了多个对应 "Event" 的数据。我知道运行时间大于定时器运行时间。但是我希望每个线程都必须等待在它之前启动的其他线程完成。
--可能的解决方案--
我创建全局静态 bool 变量 nad 分配它的真实。在我的事件中将其添加到 if 条件中,然后我将其分配为 false 直到 foreach 循环结束。
private static bool adminForElapsedEvent = true;
private void tmrAPACSEvent_Elapsed(object sender, ElapsedEventArgs e)
{
Library.WriteErrorLog("tmrAPACSEvent ticked and some job has been done successfully");
try
{
var UnProcessedEvents = BLCustomService.GetCustomEvents();
//Library.WriteErrorLog("tmrAPACSEvent ticked and some job has been done successfully" + UnProcessedEvents.Count);
if (UnProcessedEvents != null || adminForElapsedEvent)
{
adminForElapsedEvent = false;
// doing some wordks
adminForElapsedEvent = true;
}
}
catch (Exception exception)
{
Library.WriteErrorLog("Error 96: " + exception.StackTrace);
}
}
此方法第一次有效,但几分钟后 Elapse 事件再次运行,并重复插入。
您可以尝试的第一件事:设置 tmrAPACSEvent.Enabled = false
而不是 adminForElapsedEvent = false;
。那么你甚至不需要全局变量。
这不是 fool-proof,因为您 运行 处于竞争状态。所以下一个建议是锁定你的代码。但是不要使用普通锁,使用 Mutex 我发现它可以提供更好的资源访问控制。所以你的代码现在看起来像这样:
// Create a new Mutex. The creating thread does not own the mutex.
private static Mutex mux = new Mutex();
private void tmrAPACSEvent_Elapsed(object sender, ElapsedEventArgs e)
{
Library.WriteErrorLog("tmrAPACSEvent ticked and some job has been done successfully");
try
{
var UnProcessedEvents = BLCustomService.GetCustomEvents();
if (UnProcessedEvents != null)
{
tmrAPACSEvent.Enabled = false;
// Wait until it is safe to enter, and do not enter if the request times out.
if (mux.WaitOne(7000))
{
// do work
// note this is inside the mutex so that the timer is guaranteed enabled, even for just a moment
tmrAPACSEvent.Enabled = true;
}
}
}
catch (Exception exception)
{
Library.WriteErrorLog("Error 96: " + exception.StackTrace);
}
}
我用 C# 创建了 windows 服务。我使用 timer elapsed 方法对数据库执行一些 CRUD 操作。例如
tmrAPACSEvent = new Timer(10000);
tmrAPACSEvent.Elapsed += new ElapsedEventHandler(tmrAPACSEvent_Elapsed);
tmrAPACSEvent.Enabled = true;
我在 OnStart 方法中创建了这个计时器,事件是
private void tmrAPACSEvent_Elapsed(object sender, ElapsedEventArgs e)
{
Library.WriteErrorLog("tmrAPACSEvent ticked and some job has been done successfully");
try
{
var UnProcessedEvents = BLCustomService.GetCustomEvents();
if (UnProcessedEvents != null)
{
foreach (EventData eventData in UnProcessedEvents)
{
Library.WriteErrorLog(BLCustomService.ChangeEventStatus(eventData).ToString());
Library.WriteErrorLog(eventData.EventId.ToString());
var ed = new EventData()
{
dtRealDateTime = eventData.dtRealDateTime,
dwCardNumber = eventData.dwCardNumber,
strHolderName = eventData.strHolderName,
strInitObjName = eventData.strInitObjName
};
ed = BLCustomService.AddEvent(ed);
}
Library.WriteErrorLog("Events added");
}
}
catch (Exception exception)
{
Library.WriteErrorLog("Error 96: " + exception.StackTrace);
}
}
当我启动服务时,事件并行进行,并且我在数据库中获得了多个对应 "Event" 的数据。我知道运行时间大于定时器运行时间。但是我希望每个线程都必须等待在它之前启动的其他线程完成。
--可能的解决方案-- 我创建全局静态 bool 变量 nad 分配它的真实。在我的事件中将其添加到 if 条件中,然后我将其分配为 false 直到 foreach 循环结束。
private static bool adminForElapsedEvent = true;
private void tmrAPACSEvent_Elapsed(object sender, ElapsedEventArgs e)
{
Library.WriteErrorLog("tmrAPACSEvent ticked and some job has been done successfully");
try
{
var UnProcessedEvents = BLCustomService.GetCustomEvents();
//Library.WriteErrorLog("tmrAPACSEvent ticked and some job has been done successfully" + UnProcessedEvents.Count);
if (UnProcessedEvents != null || adminForElapsedEvent)
{
adminForElapsedEvent = false;
// doing some wordks
adminForElapsedEvent = true;
}
}
catch (Exception exception)
{
Library.WriteErrorLog("Error 96: " + exception.StackTrace);
}
}
此方法第一次有效,但几分钟后 Elapse 事件再次运行,并重复插入。
您可以尝试的第一件事:设置 tmrAPACSEvent.Enabled = false
而不是 adminForElapsedEvent = false;
。那么你甚至不需要全局变量。
这不是 fool-proof,因为您 运行 处于竞争状态。所以下一个建议是锁定你的代码。但是不要使用普通锁,使用 Mutex 我发现它可以提供更好的资源访问控制。所以你的代码现在看起来像这样:
// Create a new Mutex. The creating thread does not own the mutex.
private static Mutex mux = new Mutex();
private void tmrAPACSEvent_Elapsed(object sender, ElapsedEventArgs e)
{
Library.WriteErrorLog("tmrAPACSEvent ticked and some job has been done successfully");
try
{
var UnProcessedEvents = BLCustomService.GetCustomEvents();
if (UnProcessedEvents != null)
{
tmrAPACSEvent.Enabled = false;
// Wait until it is safe to enter, and do not enter if the request times out.
if (mux.WaitOne(7000))
{
// do work
// note this is inside the mutex so that the timer is guaranteed enabled, even for just a moment
tmrAPACSEvent.Enabled = true;
}
}
}
catch (Exception exception)
{
Library.WriteErrorLog("Error 96: " + exception.StackTrace);
}
}