Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 如何在windows服务中使用Threadpool.QueueUserWorkItem?_Multithreading_C# 4.0_Windows Services_Queueuserworkitem - Fatal编程技术网

Multithreading 如何在windows服务中使用Threadpool.QueueUserWorkItem?

Multithreading 如何在windows服务中使用Threadpool.QueueUserWorkItem?,multithreading,c#-4.0,windows-services,queueuserworkitem,Multithreading,C# 4.0,Windows Services,Queueuserworkitem,我有一个使用Threadpool.QueueUserWorkItem的windows服务。该服务连接到多个客户端数据库,获取数据,转换为XLS,并将文件发送到相应的FTP 关于下面的代码,我有3个问题: private static System.Timers.Timer aTimer = new System.Timers.Timer(50000); public void OnStart(string[] args) { CLE.WriteToEve

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

关于下面的代码,我有3个问题:

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.
        }
  • 我是否正确使用Threadpool.QueueUserWorkItem
  • 我是否需要在代码中的任何位置使用锁来避免问题?如果是,地点和目标
  • 代码中是否有不正确的地方?如果是,如何处理
  • 代码:

    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.
            }
    
    private static System.Timers.Timer aTimer=新系统.Timers.Timer(50000);
    公共void OnStart(字符串[]args)
    {
    CLE.WriteToEventLog(“服务已启动”);
    尝试
    {
    aTimer.Appead+=新的ElapsedEventHandler(执行时间属性);
    aTimer.Enabled=true;
    }
    捕获(例外情况除外)
    {
    CLE.WriteToEventLog(“启动服务时出错:+ex.Message”);
    }
    }
    私有void性能时间属性(对象源,ElapsedEventArgs e)
    {
    CLE.WriteToEventLog(“计时器操作已启动”);
    Clients objClient=新客户端();
    List objClientList=Clients.GetClientList();
    foreach(ObjClient列表中的变量列表)
    {
    QueueUserWorkItem(新的WaitCallback(SendFileToClient),列表);
    }                
    }
    私有void SendFilesToClient(对象状态信息)
    {
    CLE.WriteToEventLog(“已启动向客户端发送文件”);
    客户机oClient=(客户机)状态信息;
    CLE.WriteToEventLog(“开始处理客户端:+oClient.ClientName+”,ClientId:+oClient.ClientId);
    connectionString=App.Database.PrimaryConnectionString(oClient.ClientId);
    string reports=oClient.reports;
    string[]values=reports.Split(',')。选择(sValue=>sValue.Trim()).ToArray();
    foreach(值中的字符串项)
    {
    //根据客户端id向FTP发送数据
    }
    //此时,所有报告都将发送到FTP。我们将使用LastExecutionDateTime+1小时更新数据库。这将用作下一次执行的所有报告的DateFrom参数。
    }
    

    该服务运行良好,我得到了适当的结果,但我需要确保我做得正确,不会在以后遇到问题。

    我假设您的服务将继续运行,而不是“一个完成”。如果是,请注意,
    System.Timers.Timer
    类的属性默认设置为
    true
    。这仅仅意味着,每当50秒间隔过去时(50000毫秒=50秒),计时器将继续引发
    已用事件。如果您确信所有
    SendFilesToClient
    操作都在下一个间隔时间过去之前的大量时间内完成,那么您应该可以。然而,我不会打赌。如果数据库在网络上,网络断开怎么办?如果服务在较慢的系统上运行,或者在内核较少的系统上运行,并且所有工作都没有及时完成,该怎么办

    您可以通过如下方式关闭
    AutoReset
    功能来解决此问题

    private static var aTimer = new System.Timers.Timer(50000) { AutoReset = false };
    
    这意味着
    已用事件将只触发一次。在
    performtimeropertion
    中,只需将
    Enabled
    属性重置为
    true
    即可在退出前重新启动计时器

    但这是一个不完整的解决方案,因为在计时器触发另一个
    已用事件之前,线程可能仍然需要很长时间才能完成。在这种情况下,您可能希望使用
    ManualResetEvent
    在每个线程完成时发出信号,并暂停退出
    performtimeropertion
    (并重置计时器),直到出现这种情况。比如说,

    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;
    }
    
    以这种方式,
    performtimeropertion
    将阻止调用,直到所有工作线程(例如,
    SendFilesToClient
    )发出完成的信号。此时,重置计时器并在下一个间隔重复


    对不起,时间太长了。希望能有帮助。

    刚刚在@Gray做了这件事。是C.NET 4.0我觉得这很好。关于你的问题#2,不应该有任何锁定的必要,因为你的线程完全独立运行。当您协调对共享资源的访问时,锁是必要的,但在这种情况下,每个工作线程都有自己的数据库连接,并且在一组不同的“东西”上运行。谢谢@GalacticCowboy!一点也不,马特。这是很好的解释。另外,仅供参考,此服务需要每1小时运行一次,以便将文件发送到FTP。因此,在完成上一个任务之前,我看不到服务开始运行有任何问题。这有什么区别吗?我是否仍应将您的解决方案(实现自动重置和手动重置)作为最佳实践?有关于锁定的信息吗?谢谢假设前一个任务仍在工作,新任务已启动。您正在打开数据库连接吗?您可以同时打开的连接数可能有限制。收件人呢?如果他们在第一个任务之前从第二个任务获取文件,这是问题吗?发生此类事件的可能性可能很小,但一个稳健的系统会处理此类问题。你比我更了解你的系统,所以用你的工程判断。如果
    performtimeropertion
    通常不超过几分钟,我怀疑您没有问题。