1

I am new to C# programming and I have a task to make a process from single thread to multithreaded. I am using C#3.5 version and implementing threadpool in the code. I have searched about threadpool and did some changes but it is not working. When I again searched in the internet I think I wrote partial code upto only queueing user workitems, I am not understanding how to execute the threads.

Shown here is the code I wrote, please don't hesitate to correct me if the code is wrong, I am very new to C# coding.

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);
                }


            }
  • That doesn't look like partial code to me. It should work. What indicates that it doesn't work? Did you do a breakpoint on process()? – Tyress Feb 22 '16 at 07:53
  • Are you waiting on the main thread ? I assume so. If not the queued threads may never get to execute. – Venki Feb 22 '16 at 07:59
  • See this http://stackoverflow.com/questions/14515207/whats-the-proper-way-to-use-a-threadpool – Venki Feb 22 '16 at 07:59

2 Answers2

0

You don't have to do anything more. By calling QueueUserWorkItem you are saying that you want to execute a give method in a thread that is managed by a thread pool. However, you don't have any guarantee that it will be executed immediately and it is how a thread pool works. Your method will be executed when a thread pool thread is available.

In the first line of your code you call ThreadPool.SetMaxThreads(6, 6); Because of that no more than 6 thread pool threads will be active at the same time. All requests, to execute something in a thread pool, above this limit will be queued. So, maybe you made so many requests that some of them are simply waiting for their turn.

Besides you have to keep in mind that there might be another code that also uses a thread pool. In this case your requests need to compete for thread pool threads.

UPDATE (after discussion):

Try to put a breakpoint inside a process method. A debugger will stop there and it will prove that process method is really executed. However, there is probably some bug in your code and it is why you don't see e-mails being set

Michał Komorowski
  • 6,198
  • 1
  • 20
  • 24
  • The method process in my code takes the parameters and render a report in pdf format based on the parameters and will send mail and also move that pdf file from one path to another. my problem is it is looping in the above code but it is not going to the method process to do the gerating pdf and mailing as said above. – SAILENDRA SUDA Feb 22 '16 at 09:09
  • How do you know that _process_ method is not executed? Please attach the code of this method. – Michał Komorowski Feb 22 '16 at 09:12
  • @SAILENDRA - Thanks, could you also answer how you know that _process_ is not executed? Did you try to put a breakpoint inside this method? – Michał Komorowski Feb 22 '16 at 10:02
  • @micheal-yes I used a breakpoint to check . At first I executed the job normally without breakpoint,I did not received any mails so kept a breakpoint to see what happened. – SAILENDRA SUDA Feb 22 '16 at 10:05
  • @SAILENDRA And what did happenen? Did debugger stop on this breakpoint? – Michał Komorowski Feb 22 '16 at 10:07
  • Yeah debugger stopped at breakpoint, i pressed F11 thorougout and it just went into for loop and never went to process method ,came out from loop and finished the execution without error. – SAILENDRA SUDA Feb 22 '16 at 10:11
  • @SAILENDRA I'm not sure if I understand you. Was this breakpoint insde _process_ method or somewhere else. I don't see any for look in _process_ method. – Michał Komorowski Feb 22 '16 at 10:17
  • Sorry if I confused you, the for loop in public void calss. In the below code for (int i = 0; i < aq.Count; i++) { object j = aq[i]; ThreadPool.QueueUserWorkItem(new WaitCallback(process), j); } – SAILENDRA SUDA Feb 22 '16 at 10:36
  • So now I suggest to put a breakpoint inside _process_ method. I'm quite sure that a debugger will stop there what will prove you that your method is executed. However, there is probably some bug in _process_ method and it is why you don't see e-mails being set. – Michał Komorowski Feb 22 '16 at 11:00
  • @micheal- yeah it is going to process method, I guess there is some issue in the code in the process method.Thank You. – SAILENDRA SUDA Feb 22 '16 at 13:13
  • @SAILENDRA You are welcome. Please accept my answer. – Michał Komorowski Feb 22 '16 at 13:18
0

One reason I think that your code may not execute is that you have a race condition of some sort between the thread executing and your program ending. How long is your code? If you're just beginning to learn C#, I have a feeling you are coding a console app and your code is mostly on the Main() method and consists of a few lines. If you do ThreadPool.QueueUserWorkItem() on a short application and the end of the Main() method is reached immediately, your code may never execute!

To avoid this, you can add a sleep for a second before the Main() method ends, e.g.:

Thread.Sleep(1000);
Tyress
  • 3,573
  • 2
  • 22
  • 45
  • 1
    If you want to wait for something, never use `Sleep`. For normal threads use `Join`. Waiting on all threads in a threadpool is a bit more complicated. But the second answer here is pretty comprehensive: http://stackoverflow.com/questions/6529659/wait-for-queueuserworkitem-to-complete (good thinking about the program stopping before the work is done btw!) – Roy T. Feb 22 '16 at 08:45
  • No my code considerably big, the method process mentioned above takes those parameters and render a pdf format report and mails it.The execution is not going to process method at all. – SAILENDRA SUDA Feb 22 '16 at 09:12
  • @RoyT. I guess I assumed he was a newbie so I gave an unsophisticated workaround, although thinking about it now it may not have been a good thing to suggest `Sleep` in any case :P – Tyress Feb 22 '16 at 09:42
  • @SAILENDRASUDA how long your code for process() is is not at all important though, what matters is how long the *calling* code is before it stops! – Tyress Feb 22 '16 at 11:19
  • You said in another comment "Yeah debugger stopped at breakpoint, i pressed F11 thorougout and it just went into for loop and never went to process method ,came out from loop and finished the execution without error." When you say *finished execution*, does that mean the program has ended? How long did it take? That's what I'm referring to here... – Tyress Feb 22 '16 at 11:21