Zaki
Zaki

Reputation: 5600

Run a Method In thread as it is really slow

If i have a method that returns a string as follow :

 public string ExecuteCommandSync(object command)
        {
            string result = "";
            try
            {
                System.Diagnostics.ProcessStartInfo procStartInfo =
                    new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);


                procStartInfo.RedirectStandardOutput = true;
                procStartInfo.UseShellExecute = false;

                procStartInfo.CreateNoWindow = true;

                System.Diagnostics.Process proc = new System.Diagnostics.Process();
                proc.StartInfo = procStartInfo;
                proc.Start();

                result = proc.StandardOutput.ReadToEnd();

                Console.WriteLine(result);
            }
            catch (Exception objException)
            {
                MessageBox.Show("error : " + objException.Message);
            }

            return result;
        } 

Now this works fine for small data but if i have large data it hangs..

If I put this in thread would that make it quicker for large data or at least improve ,as Im completely new to threading and i dont know how to return the result as string again with thread...

can someone help please.

thanks

EDIT :

It is a c# winform application running on windows 7. Basically the idea is to invoke the cmd command and run a command ... This is the error i get when running from visual studio :

The CLR has been unable to transition from COM context 0x8d85c0 to COM context 0x8d8730 for 60 seconds. The thread that owns the destination context/apartment is most likely either doing a non pumping wait or processing a very long running operation without pumping Windows messages. This situation generally has a negative performance impact and may even lead to the application becoming non responsive or memory usage accumulating continually over time. To avoid this problem, all single threaded apartment (STA) threads should use pumping wait primitives (such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.

EDIT 2:: Ok here is what i have done so far

public string ExecuteCommandSync(object command)
        {
            string result = "";
            try
            {

                backgroundWorker1.RunWorkerAsync(command);
            }
            catch (Exception objException)
            {
                MessageBox.Show("error : " + objException.Message);
            }

            return result;
        }
  private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            string result;
            Thread.Sleep(300);
            object command = (object)e.Argument;
            System.Diagnostics.ProcessStartInfo procStartInfo =
                   new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);


            procStartInfo.RedirectStandardOutput = true;
            procStartInfo.UseShellExecute = false;

            procStartInfo.CreateNoWindow = true;

            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo = procStartInfo;
            proc.Start();

            result = proc.StandardOutput.ReadToEnd();
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            results = (string)e.Result;
        }

and then i call it using :

string result1 = ExecuteCommandSync(command);

Upvotes: 0

Views: 899

Answers (4)

ispiro
ispiro

Reputation: 27723

Add to your program:

BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();

And also:

void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    string result = (string)e.Result;
    //do what you need with it.
}

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    //do your work here
    e.Result = yourResult;
}

But also keep in mind what others have said: A thread will not run quicker than a non-threaded program. The benefit will be that the program won't "hang".

Upvotes: 2

user1145202
user1145202

Reputation: 147

You could use an event. When your thead has finished, it throws an event and it give the String to the event.

Upvotes: 0

Jon Hanna
Jon Hanna

Reputation: 113382

Another thread won't make it run faster, because the time taken to wait for an application to do something isn't affected by which tread is doing it.

However, that isn't your problem, your problem is that the UI thread is taking too long. Non-UI threads can merrily take years to do something without triggering that error, so it will indeed solve the problem.

Another approach is to not do ReadToEnd() but to read and process smaller chunks as they come. Depending on the nature of the program you are calling into this could solve all your issues (if the program starts responding quickly and the reason you've such a delay is that it's sending a massive amount of data to output) or not (if the program takes a few minutes to send a single byte, then you've the same problem as before.

The two can be combined, with another thread reading chunks at a time from the called program's standard output, and updating state accordingly as it goes.

Upvotes: 0

Hans Passant
Hans Passant

Reputation: 942348

            result = proc.StandardOutput.ReadToEnd();

That's the statement that causes your main UI thread to hang. The ReadToEnd() call won't complete until the process you started stops running. The "The CLR has been unable to transition from COM context..." message is just a warning, triggered when the debugger also noticed that your main thread went dead. It is guessing it might be caused by a deadlock.

Threading is indeed your solution, simply move this code into the DoWork event handler for a BackgroundWorker. Read this MSDN page for guidance.

Upvotes: 4

Related Questions