【问题标题】:How to execute the threadpool after Queueing user work items in C#?在 C# 中排队用户工作项后如何执行线程池?
【发布时间】:2016-02-22 07:44:23
【问题描述】:

我是 C# 编程的新手,我的任务是创建一个从单线程到多线程的进程。我正在使用 C#3.5 版本并在代码中实现线程池。我搜索了线程池并做了一些更改,但它不起作用。当我再次在互联网上搜索时,我想我只写了部分代码来排队用户工作项,我不明白如何执行线程。

这里显示的是我写的代码,如果代码有错误请不要犹豫纠正我,我对 C# 编码非常陌生。

ThreadPool.SetMaxThreads(6, 6);

try
{
    // Assign the values to the report parameters
    for (int i = 0; i < aq.Count; i++)
    {
        object j = aq[i];
        ThreadPool.QueueUserWorkItem(new WaitCallback(process), j);
    }
}            
   private void process(object i)
    {

        List<Report> aq = new List<Report>();
        ReportEnv env = null;
        ParameterValue[] paramval;

        List<Report> list = new List<Report>();
        Report al = null;

        using (OleDbDataAdapter oleDA = new OleDbDataAdapter())
        using (DataTable dt = new DataTable())
        {
            oleDA.Fill(dt, i);

            foreach (DataRow _row in dt.Rows)
            {
                al = new Report();

                al.EmailAttachmentMsg = _row["AttachmentMsg"].ToString();
                al.reportName = _row["Repo"].ToString();
                al.AccountNumber = _row["Number"].ToString();
                al.AccountGroupCode = _row["GroupCode"].ToString();
                al.EmailTo = _row["To"].ToString().Split(';');
                al.ReportScheduleId = _row["ReportScheduleId"].ToString();
                al.Frequency = _row["Frequency"].ToString();
                al.ColcoContactTelephone = _row["ColcoContactTelephone"].ToString();

                list.Add(al);
            }
        }
        // aq = Populatereport(Dts.Variables["vnSource_SQL_Result"].Value);
        env = PopulateEnvironment(Dts.Variables["vnEnvironment"].Value);
        aq = list;


        paramval = new ParameterValue[2];
        paramval[0] = new ParameterValue();
        paramval[0].Name = "PRM_CustomerDetails";
        paramval[0].Value = aq[0].AccountNumber;
        paramval[1] = new ParameterValue();
        paramval[1].Name = "PRM_Startdate";
        paramval[1].Value = aq[0].StartDate;


        //Rendering the report begins

        ReportExecutionService rs = new ReportExecutionService();
        rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
        rs.Url = env.SSRSServerUrl.ToString();


        //Load the report options
        rs.LoadReport(aq[0].ReportPath, null);
        rs.SetExecutionParameters(paramval, aq[0].CultureCode);



        // Set the filename

        String filename = aq[0]. Number + "_" + env.Code + "_" + "_" + aq[0].Name +
            DateTime.UtcNow.ToString("_dd-MM-yyyy_hh-mm-ss.fff");

        //Render the report and generate pdf
        Byte[] results;
        string encoding = String.Empty;
        string mimeType = String.Empty;
        string extension = String.Empty;
        Warning[] warnings = null;
        string[] streamIDs = null;
        string deviceInfo = null;
        results = rs.Render(aq[0].ReportFormat, deviceInfo, out extension, out encoding, out mimeType, out warnings, out streamIDs);


        //Write the file into the directory
        using (FileStream stream = File.OpenWrite(@env.wipPath + filename))
        {

            stream.Write(results, 0, results.Length);
         }


            if (SendEmail(env.From, aq[0].To,  env.Subject, aq[0].Attachment, env.Server, false,  filename, env.TimeOut) == true)
            {
                // Move report file from WIP to Processed
                File.Move(@env.oldPath + filename, @env.newPath + filename);
                }


            }

【问题讨论】:

  • 对我来说这看起来不像是部分代码。它应该工作。什么表明它不起作用?你在 process() 上做了断点吗?
  • 你在等待主线程吗?我假设是这样。如果不是,排队的线程可能永远无法执行。

标签: c# multithreading


【解决方案1】:

我认为您的代码可能无法执行的一个原因是您在线程执行和程序结束之间有某种race condition。你的代码有多长?如果您刚开始学习 C#,我感觉您正在编写一个控制台应用程序,并且您的代码主要在 Main() 方法上,并且由几行组成。如果您在一个简短的应用程序上执行ThreadPool.QueueUserWorkItem() 并且立即到达Main() 方法的末尾,您的代码可能永远不会执行!

为避免这种情况,您可以在 Main() 方法结束之前添加一秒钟的睡眠,例如:

Thread.Sleep(1000);

【讨论】:

  • 如果你想等待什么,永远不要使用Sleep。对于普通线程,使用Join。等待线程池中的所有线程有点复杂。但是这里的第二个答案非常全面:stackoverflow.com/questions/6529659/…(顺便说一句,程序在工作完成之前就停止了!)
  • 不,我的代码很大,上面提到的方法过程将这些参数渲染为pdf格式的报告并发送出去。执行根本不去处理方法。
  • @RoyT。我想我以为他是新手,所以我给出了一个简单的解决方法,尽管现在考虑一下,无论如何建议Sleep 可能不是一件好事:P
  • @SAILENDRASUDA 你的 process() 代码多长时间并不重要,重要的是 调用 代码在它停止之前有多长时间!
  • 您在另一条评论中说“是的,调试器在断点处停止,我按下 F11 thorougout,它刚刚进入 for 循环,从未进入处理方法,从循环中出来并完成执行而没有错误。”当您说执行完毕时,是否意味着程序已经结束?花了多长时间?这就是我在这里指的......
【解决方案2】:

您无需再做任何事情。通过调用QueueUserWorkItem,您是说您想在由线程池管理的线程中执行给定方法。但是,您不能保证它会立即执行,这就是线程池的工作方式。当线程池线程可用时,您的方法将被执行。

在您的代码的第一行中,您调用ThreadPool.SetMaxThreads(6, 6);,因为不会有超过 6 个线程池线程同时处于活动状态。所有在线程池中执行某事的请求,超过此限制将被排队。所以,也许你提出了太多请求,以至于他们中的一些人只是在等待轮到他们。

此外,您必须记住,可能还有其他代码也使用线程池。在这种情况下,您的请求需要竞争线程池线程。

更新(讨论后):

尝试在process 方法中放置断点。调试器将停在那里,它将证明process 方法确实被执行了。但是,您的代码中可能存在一些错误,这就是您看不到设置电子邮件的原因

【讨论】:

  • 我的代码中的方法过程获取参数并根据参数以 pdf 格式呈现报告,并将发送邮件并将该 pdf 文件从一个路径移动到另一个路径。我的问题是它在上面的代码中循环,但它不会像上面所说的那样去执行生成 pdf 和邮件的方法过程。
  • 你怎么知道process方法没有被执行?请附上该方法的代码。
  • @SAILENDRA - 谢谢,您能否回答一下您是如何知道 process 未执行的?您是否尝试在此方法中放置断点?
  • @micheal-yes 我用断点检查 .一开始我正常执行作业,没有断点,我没有收到任何邮件,所以保留一个断点看看发生了什么。
  • @SAILENDRA 发生了什么?调试器是否在此断点处停止?
猜你喜欢
  • 2013-07-09
  • 2011-06-20
  • 2011-06-09
  • 2020-10-16
  • 2013-07-31
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多