如何在Windows服务中使用Threadpool.QueueUserWorkItem? [英] How to use Threadpool.QueueUserWorkItem in a windows service?

查看:148
本文介绍了如何在Windows服务中使用Threadpool.QueueUserWorkItem?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Windows服务,我使用Threadpool.QueueUserWorkItem。该服务连接到多个客户端数据库,抓取数据,转换为XLS并将文件发送到相应的FTP。

I have a windows service where I am using Threadpool.QueueUserWorkItem. The service connects to multiple client databases, grabs data, converts to XLS and send files to the corresponding FTP.

我对以下代码有3个问题: / strong>

I have 3 questions regarding the code below:


  1. 我是否正确使用Threadpool.QueueUserWorkItem?

  2. 我需要使用锁定代码中的任何地方以避免问题?如果是,在哪里和什么对象。

  3. 代码中有什么不正确吗?如果是,如何处理?

代码: b

private static System.Timers.Timer aTimer = new System.Timers.Timer(50000);

public void OnStart(string[] args)
        {
            CLE.WriteToEventLog("Service Started");
            try
            {
                aTimer.Elapsed += new ElapsedEventHandler(PerformTimerOperation);
                aTimer.Enabled = true;
            }
            catch (Exception ex)
            {
                CLE.WriteToEventLog("Error Starting Service: " + ex.Message);
            }
        }

private void PerformTimerOperation(object source, ElapsedEventArgs e)
        {
            CLE.WriteToEventLog("Timer Operation Started");
                Clients objClient = new Clients();
                List<Clients> objClientList = Clients.GetClientList();

                foreach (var list in objClientList)
                {
                    ThreadPool.QueueUserWorkItem(new WaitCallback(SendFilesToClient), list);
                }                
        }

private void SendFilesToClient(Object stateInfo)
        {
            CLE.WriteToEventLog("Send Files To Client Started");
            Clients oClient = (Clients)stateInfo;
            CLE.WriteToEventLog("Start Proecessing Client: " + oClient.ClientName + ", ClientId: " + oClient.ClientId);

            connectionString = App.Database.PrimaryConnectionString(oClient.ClientId);

            string reports = oClient.Reports;
            string[] values = reports.Split(',').Select(sValue => sValue.Trim()).ToArray();

            foreach (string item in values)
            {
    //Send data to FTP based on cliend id
            }
            // At this point all reports are being sent to the FTP. We will update the database with LastExecutionDateTime + 1 hour. This will be used as DateFrom param for all reports for the next execution.
        }

服务工作正常,我得到适当的结果,但我需要确保

The service works fine and I get appropriate results, but I need to make sure I am doing it right and don't run in to issues later.

推荐答案

我假设你的服务是为了保持运行而不是一刀切。如果是,请注意 AutoReset System.Timers.Timer 类的$ c> 属性设置为 true 。这仅仅意味着每当50秒间隔(50000毫秒= 50秒),定时器将继续提高 Elapsed 事件。如果您确实确定在下一个时间间隔之前的所有 SendFilesToClient 操作在大量时间内完成,则您应该确定。但是,我不打赌它。如果数据库在网络上并且网络关闭怎么办?如果服务在较慢的系统或核心较少的系统上运行,并且所有工作未及时完成,该怎么办?

I'm assuming your service is meant to keep running as opposed to being "one-and-done". If so, please note that the AutoReset property of the System.Timers.Timer class is set to true by default. This simply means that the timer will continue to raise the Elapsed event each time the 50-second interval elapses (50000 milliseconds = 50 seconds). If you know for sure that all of the SendFilesToClient operations complete in plenty of time before the next interval elapses, then you should be ok. However, I wouldn't bet on it. What if the database is on the network and the network goes down? What if the service is running on a slower system or one with fewer cores and all the work isn't completed in time?

您可以通过关闭 AutoReset 功能。

private static var aTimer = new System.Timers.Timer(50000) { AutoReset = false };

这意味着 Elapsed 一旦。在 PerformTimerOperation 内,只需将启用属性重置为 true 在退出之前重新启动计时器。

This means the Elapsed event will only fire once. Inside the PerformTimerOperation, simply reset the Enabled property to true to restart the timer before exiting.

但这是一个不完整的解决方案,因为线程可能需要很长时间才能触发另一个 事件。在这种情况下,您可能需要使用 ManualResetEvent 来通知每个线程完成并挂起退出 PerformTimerOperation 复位定时器)直到发生。例如,

But this is an incomplete solution because the threads may still take too long to finish before the timer triggers another Elapsed event. In this case, you might want to use a ManualResetEvent to signal when each thread is complete and suspend exiting PerformTimerOperation (and resetting the timer) until that occurs. For example,

private void PerformTimerOperation(object source, ElapsedEventArgs e)
{
    List<Clients> objClientList = new Clients().GetClientList();
    List<ManualResetEvent> handles = new List<ManualResetEvent();

    foreach (var list in objClientList)
    {
        // Create an MRE for each thread.
        var handle = ManualResetEvent(false);

        // Store it for use below.
        handles.Add(handle);

        // Notice two things:
        // 1.  Using new WaitCallback(...) syntax is not necessary.
        // 2.  Thread argument is now a Tuple object.
        ThreadPool.QueueUserWorkItem(SendFilesToClient, Tuple.Create(list, handle));
    }

    // Wait for threads to finish.
    WaitHandle.WaitAll(handles.ToArray());

    // Reset the timer.
    aTimer.Enabled = true;
}

现在更新 SendFilesToClient

Now update SendFilesToClient.

private void SendFilesToClient(Object stateInfo)
{
    // The parameter is now a Tuple<T1, T2>, not a Clients object.
    var tuple = (Tuple<Clients, ManualResetEvent>)stateInfo;

    try
    {
        Clients oClient = tuple.Item1;

        // Do your work here...
    }
    catch (Exception ex)
    {
        // Handle any exception here.
    }
    finally
    {
        // Signal that the work is done...even if an exception occurred.
        // Otherwise, PerformTimerOperation() will block forever.
        ManualResetEvent mreEvent = tuple.Item2;
        mreEvent.Set();
    }
}

PerformTimerOperation 将在 WaitHandle.WaitAll() 调用,直到所有工作线程,例如 SendFilesToClient ,表示它们已完成。此时,您重置计时器,并在下一个间隔重复。

In this fashion, the PerformTimerOperation will block on the WaitHandle.WaitAll() call until all the worker threads, e.g., SendFilesToClient, signal that they are finished. At that point, you reset the timer and repeat on the next interval.

对不起,这么长。希望它有帮助。

Sorry this is so long. Hope it helps.

这篇关于如何在Windows服务中使用Threadpool.QueueUserWorkItem?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆