I recently found that the cause of an obscure bug was due to Process.Start. The method triggered a pump in the event queue while the process was starting, which in turn made code run that was dependent on the process being started.
The bug seemed to be timing related since it did not happen consistently, and was quite difficult to reproduce. Since we have more places in the code where we use Process.Start, and we might very well use it more in the future, I thought it would be good to get to the bottom of how to trigger it more consistently.
We created a standalone winforms project with a single button, here is the click eventhandler:
private void button1_Click(object sender, EventArgs e) {
this.BeginInvoke(new MethodInvoker(() => { MessageBox.Show("Hello World"); }));
var process = new System.Diagnostics.Process() { EnableRaisingEvents = true };
process.Exited += CurrentEditorProcess_Exited;
// Does pump
process.StartInfo = new System.Diagnostics.ProcessStartInfo(#"C:\Users\micnil\Pictures\test.png");
// Does not pump
//process.StartInfo = new System.Diagnostics.ProcessStartInfo("Notepad.exe");
process.Start();
Thread.Sleep(3000);
Console.WriteLine("Done");
}
Running this code will:
show the messagebox,
finish opening the test image,
After exiting the messagebox, the program will sleep 3 seconds and then log "Done".
If I replace the ProcessStartInfo argument with "Notepad.exe" instead, the code will:
start Notepad,
log Done,
Show the message box.
This can be reproduced consistently. The problem is, the program that we are starting is more similar to notepad. It is our own custom text editor built in WPF. So why does starting our executable sometimes trigger a pump, but I cannot make Notepad do the same?
We found a few others that has been hit by the same problem:
Which blocking operations cause an STA thread to pump COM messages?
No answer to why
Process.Start causes processing of Windows Messages:
Qouting Dave Andersson
ShellExecuteEx may pump window messages when opening a document in its
associated application, specifically in the case where a DDE
conversation is specified in the file association.
Additionally, ShellExecuteEx may create a separate thread to do the
heavy lifting. Depending on the flags specified in the
SHELLEXECUTEINFO structure, the ShellExecuteEx call may not return
until the separate thread completes its work. In this case,
ShellExecuteEx will pump window messages to prevent windows owned by
the calling thread from appearing hung.
You can either ensure that the variables in question are initialized
prior to calling Process.Start, move the Process.Start call to a
separate thread, or call ShellExecuteEx directly with the
SEE_MASK_ASYNCOK flag set.
"May create a thread" - How do I know when?, "You can either ensure that the variables in question are initialized prior to calling Process.Start" - How?
We solved the problem by setting process.StartInfo.UseShellExecute = false before starting the process. But the question remains, does anyone know how to write a minimal program that would trigger a pump from starting a executable like Notepad?
Update:
Done some more investigation and have two new findings:
private void button1_Click(object sender, EventArgs e) {
this.BeginInvoke(new MethodInvoker(() => {
Log("BeginInvoke");
}));
string path = Environment.GetEnvironmentVariable("PROCESS_START_EXE");
var process = new System.Diagnostics.Process() { EnableRaisingEvents = true };
process.Exited += CurrentEditorProcess_Exited;
process.StartInfo = new System.Diagnostics.ProcessStartInfo(path, "params");
process.Start();
Thread.Sleep(3000);
Log("Finished Sleeping");
}
1:
When setting the environment variable PROCESS_START_EXE to "Notepad" the logging becomes:
BeginInvoke
Finished Sleeping
When setting the environment variable PROCESS_START_EXE to "Notepad.exe" (note the ".exe") the logging becomes:
Finished Sleeping
BeginInvoke
Which I find strange, but I don't think is related to the problem we were having. We always specify the exact path and filename to the executable, including ".exe"
2:
The scenario in which I found the bug, was that i launched the application through a Windows shortcut with a target similar to this:
C:\Windows\System32\cmd.exe /c "SET PROCESS_START_EXE=<path to custom editor> && START /D ^"<path to application directory>^" App.exe"
It first sets an environment variable with the path to the executable that is supposed to be started, and then launches the winforms application.
If I use this shortcut to launch the application, and use the environment variable to start the process, then the logging always becomes:
BeginInvoke
Finished Sleeping
This does seem like the problem we were having. Only that I couldn't reproduce it consistently every time. Why does it matter that I am setting the environment variable right before launching the application?
Note that if I use the same shortcut, but do not use the environment variable to start the process, the message loop will not pump.
Related
I have this code here that starts a process wait 8 seconds and then kill it and again.
for (int i = 0; i < 20; i++)
{
Process pro = new Process();
pro.StartInfo.FileName = #"C:\Program Files (x86)\Mozilla Firefox\firefox.exe";
pro.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
pro.Start();
Thread.Sleep(8000);
try
{
pro.Kill();
Thread.Sleep(1000);
}
catch
{
return;
}
}
As i run the application either on debug mode or direct from the .exe , it successfully starts and kills the process but it is frozen. I cant move its window around or click on other buttons..
it is frozen. I cant move its window around or click on other buttons.
That's correct. You said to put the thread to sleep.
People seem to have this strange idea that running code when buttons are pressed happens by magic. It does not happen by magic. It happens because the thread runs code that processes the "a button was clicked" message from the operating system. If you put a thread to sleep then it stops processing those messages, because it is asleep.
Putting a thread to sleep is 99% of the time the completely wrong thing to do, so just don't do it.
The right thing to do in C# 5 is to make your method async and then do an await Task.Delay(whatever). Alternatively, create a timer that ticks after some number of seconds. In the tick handling event, turn the timer off and do your logic there.
Well, my initial guess is that you are doing this all on your UI Thread. Since you make the UI thread sleep, your application will be frozen.
The obvious solution would be doing this in a new thread.
As Servy sais, this is not a great idea. You can use a Timer (https://msdn.microsoft.com/en-us/library/system.timers.timer%28v=vs.110%29.aspx) to do the waiting instead of blocking the UI thread.
The main thread of your application is a loop that constantly peeks messages from Windows message queue. It's like cooperative multi-threading - if you don't update your UI explicitly it won't do that automatically. And it won't because your program (main thread) just spawns a process then sleeps and then kills it (you don't even need that try/catch block - any exception on any thread of your application will terminate it). Sleeping within a thread blocks it. And because you sleep in the main thread (UI) you block the application from peeking from the message queue.
Sorry for the lengthy post, I just want to illustrate my situation as best as possible. Read the items in bold and check the code if you want the quick gist of the issue.
I use ClickOnce to deploy a C# application, and have opted to have my application check for updates manually using the ApplicationDeployment Class rather than letting it do the update checking for me.
The program is a specialized network scanner that searches for network devices made by the company I work for. Once the main window is loaded, a prompt is displayed asking if the user would like to scan the network. If they say Yes, a scan begins which can take a minute or two to complete depending on their network settings; otherwise it just waits for the user to do some action.
One of the last things I do in Form_Load is create a new thread that checks for updates. This had all been working fine for several months through about 12 releases and has suddenly stopped working. I didn't change the update code at all, nor change the sequence of what happens when the app starts.
In staring at the code, I think I see why it is not working correctly and wanted to confirm if what I think is correct. If it is, it begs the question as to why it DID work before - but I'm not too concerned with that either.
Consider the following code:
frmMain.cs
private void Form1_Load(object sender, EventArgs e)
{
// set up ui, load settings etc
Thread t = new Thread(new ParameterizedThreadStart(StartUpdateThread));
t.Start(this);
}
private void StartUpdateThread(object param)
{
IWin32Window owner = param as IWin32Window;
frmAppUpdater.CheckForUpdate(owner);
}
frmAppUpdater.cs
public static void CheckForUpdate(IWin32Window owner)
{
if (ApplicationDeployment.IsNetworkDeployed) {
Console.WriteLine("Going to check for application updates.");
parentWindow = owner;
ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
ad.CheckForUpdateCompleted += new CheckForUpdateCompletedEventHandler(ad_CheckForUpdateCompleted);
ad.CheckForUpdateProgressChanged += new DeploymentProgressChangedEventHandler(ad_CheckForUpdateProgressChanged);
ad.CheckForUpdateAsync();
// CAN/WILL THE THREAD CREATED IN FORM1_LOAD BE TERMINATED HERE???
}
}
When the CheckForUpdateAsync() callback completes, if no update is available the method call simply returns; if an update IS available, I use a loop to block until 2 things occur: The user has dismissed the "Would you like to scan prompt" AND no scan is currently running.
The loop looks like this, which takes place in ad_CheckForUpdateCompleted:
while (AppGlobals.ScanInProgress || AppGlobals.ScanPromptVisible) {
System.Threading.Thread.Sleep(5000);
}
I sleep for 5 seconds because I figured this was happening in a separate thread and it has seemed to work well for a while.
My main question about the above code is:
When ad.CheckForUpdateAsync(); is called from CheckForUpdate does the thread I created in Form1_Load terminate (or might it terminate)? I suspect it may because the subsequent Async call causes the method to return, and then start another thread?
The only reason I am confused is because this method WAS working for so long without hanging the application and now all of the sudden it hangs and my best effort at debugging revealed that it was that Sleep call blocking the app.
I'd be happy to post the full code for frmAppUpdater.cs if it would be helpful.
When ad.CheckForUpdateAsync(); is called from CheckForUpdate does
the thread I created in Form1_Load terminate (or might it terminate)?
If the CheckForUpdateAsync() call is asynchronous then yes, the thread will terminate, no it won't otherwise.
If you suspect the Sleep to have caused the application hang then these two variables AppGlobals.ScanInProgress and AppGlobals.ScanPromptVisible are probably always set to true! You should start looking at the code that is setting them to true and see what is going on there.
In order to avoid an application hang, you could introduce a variable to avoid sleeping indefinitely:
int nTrials = 0;
while ((AppGlobals.ScanInProgress || AppGlobals.ScanPromptVisible) && (nTrials < 5)) {
System.Threading.Thread.Sleep(5000);
nTrials++;
}
// Check the results and act accordingly
I personally do not like using Sleep for thread synchronization. .NET offers a bunch of classes that are perfect for thread synchronization, WaitHandle being one of them.
See this post at Asynchronous Delegates Vs Thread/ThreadPool?
your form load method seems to be doing synchronous work. you mention that you are using clickonce deployment. Has the binary location changed after the previous release or has permissions on this resource changed. Looks like the work (checkupdates) in the Thread is never finishing and is never handed back to the form.
as an immediate fix, I would change the Thread approach to Delegate - if you use delegate, then this becomes less of a customer issue (the form will respond to end user) but the underlying problem remains.
as the next step, i would go through http://msdn.microsoft.com/en-us/library/ms229001.aspx and do the troubleshoot
I have a weird issue:
In my C# app, I am creating another thread, like so:
Thread printThread = new Thread(printWorker);
printThread.Name = "Logger MainThread";
printThread.IsBackground = true;
printThread.Start();
When my main thread finishes, this new thread just keeps on working, although it's marked as Background.
What could be the causes for this?
This object is holding a Mutex object, not sure this may be the reason...
Any ideas anyone?
Here's the code from the printWorker method:
while (loggerIsActive)
{
LogMessage log = LoggerQueue.Dequeue();
if (log.message != null)
{
syncLogObj.WaitOne();
lock (writerobj)
{
StreamWriter sw;
if (!File.Exists(fName))
{
sw = File.CreateText(fName);
}
else
{
sw = new StreamWriter(fName, true);
}
using (sw)
{
if (log.message != "")
{
if (log.message.EndsWith("\r\n"))
{
log.message =
log.message.Substring(0, log.message.Length - 2);
}
sw.WriteLine(string.Format("[{0}][{3}][{1}] | {2}",
log.msgTime,
log.level.ToString(),
log.message,
log.sender.ToString()));
}
sw.Flush();
sw.Close();
}
}
syncLogObj.ReleaseMutex();
}
Thread.Sleep(5);
}
Try this:
Start the app through VS and exit normally. The VS should stay in Debug mode as you described. Click on Pause button (Break all) and then go to Debug->Windows->Threads. Do you see your "Logger MainThread" in the list?
If so, double-click it, it should lead you to the code line that the thread is currently executing. Step-debug from there and see why is it not terminating.
If you don't see it try looking at other threads that have not terminated and try to find the problem.
Otherwise, with those kind of problems it's always useful to monitor the program state via System.Diagnostics.Debug.Print statements (you can see them printing in the VS output window).
kill it.
Not pretty. But this isn't TV. Read on:
1) Not sure you use are using it but it appears you should be locking loggerqueue before you queue(main pgm) or dequeue(thread).
2) No need to lock writerobj with just this setting. But really you should so you can safely kill the thread not during a write:
main thread:
do everything
before close:
-lock writerobj
-printthread.abort
worker thread:
add try catch to handle threadabort exception and just quit
If you're properly doing this, you shouldn't have to use Waits and mutexes. If you are using wait properly anyway you won't need the sleep.
General advice for this application: why not log on main thread? if your logging is that busy, log results will be pretty useless.
But there are rare cases where that might be wrong. Entonces......
General advice to have threads play nice for this problem:
Main program
encapsulate logging (notably, quit flag, queue, and worker thread ref) in an object
'global snobs?' Logging is a rare excuse to use singleton patter.
start worker thread in logger object via method
main thread always calls a single method on logger object to log error
That method locks the queue and adds to it.
Use Monitor/Pulse/Wait, no sleep; full examples abound; it is worth learning
because only this thread is hitting the file anyway, unless you have multiple processes, you don't need waitone/releasemutex.
That logging method monitor.pulses an object
That frees the worker thread's monitor.wait (which is what idles the CPU instead of sleep)
lock the queue, only inside the lock dequeue the object to local ref; nothing else.
Do your normal logging code and 'exit check' loop. Add
Your logic code could leave message unwritten if queue is full on quit:
change to exit check so you can do it without an extra lock of queue:
move declaration of queued object refernce above while; set it to nothing
change logic in while to 'loggerisactive or log != null'
when your main thread finishes, in your exit code:
set the quit flag
pulse the object you're using to wait incase it's not processing the queue
Thread will fall thru.
You have a lot of stuff going on that you're obviously not showing...
Exmaple: you have syncLogObj.WaitOne();, but we don't see where syncLogObj is being declared, or used elsewhere in your program.
Plus, you don't need it... get rid of the syncLogObj thing altogether (including the "ReleaseMutex" garbage)... you already have a lock (blah) { }, and that's all you need (from what code you have displayed).
It's likely that the main thread is NOT ending, likely because of this or some other object that is keeping it open.
So, simple instructions
Get rid of syncLogObj (because you already have the "lock")
Make sure you set loggerIsActive = false somewhere.
Edit: Even more details!
From what I see - you don't need the lock (writerobj) at all, because (I'm quite sure), you only seem to have one thread that is writing to the log.
The "lock" is only there if you have two or more threads that running that code (basically).
If printworker does not finish before your main thread is done, then main will die and your printworker thread will be killed by the OS. If you want main to wait for the thread you created, then you should call printThread.Join() in main. That will get main to wait on your thread.
When main finishes your program dies and your printThread will be destroyed by the OS, It will not keep running.
From here
Background threads are identical to
foreground threads with one exception:
a background thread does not keep the
managed execution environment running.
Once all foreground threads have been
stopped in a managed process (where
the .exe file is a managed assembly),
the system stops all background
threads and shuts down.
Tony the Tiger has the right idea but additional code needs to be added to kill the thread before the application closes.
printThread.Join(1000);
if(printThread!=null && printThread.IsAlive)
printThread.Abort();
Thread.Abort();
Thread.Dispose();
That should do it if I'm not mistaken.
I need to run several instances of an external executable from my app. The average run time for this executable is about 3 minutes.
I want to redirect output from these processes, and update a progress bar in my GUI.
Of course I don't want to wait for them to return before I can continue using my app.
I think I should create a thread for every instance, and update my progress bar when a thread finishes.
Is this the right approach ?
Also, do you recommend a good resource / documentation to understand how it works ? I've found http://www.dotnetperls.com/threadpool only.
edit : these processes are network-based, ie: the run time may vary a lot depending on the link latency/bandwidth.
Concerning the progress bar, I would like to update it every time a process finishes. Is there a handler for that ? Later i will add more detailed update, based on the processes output to increase the progress done at each execution step.
edit 2 :
Thanks for your inputs. As I may have to run a lot of process (up to 20), and I don't want to saturate bandwidth, i'll run 5 in parallel max. Every time a process finishes, I increment the progress counter (for my progress bar) and I run another one until they're all completed, using :
Process p = new Process();
p.StartInfo.FileName = pathToApp;
p.EnableRaisingEvents = true;
p.Exited += OnCalibrationProcessExited;
p.Start();
private void OnCalibrationProcessExited(object sender, EventArgs e)
{
runAnotherOne function
}
Is it correct or is there a more elegant way to achieve this ?
I don't want my app to be blocked during execution of course.
Is it better to use background workers for this ?
You should be using Process and ProcessStartInfo.
You'll need to set ProcessStartInfo.UseShellExecute to false, ErrorDialog to false, RedirectStandardOutput to true (and possibly RedirectStandardError too).
You'll also need to provide a delegate to the Process object to handle to output generated by the external process through OutputDataReceived (and possibly ErrorDataReceived as well).
There's also an Exited delegate you can set that will be called whenever the process exits.
Example:
ProcessStartInfo processInfo = new ProcessStartInfo("Write500Lines.exe");
processInfo.ErrorDialog = false;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardOutput = true;
processInfo.RedirectStandardError = true;
Process proc = Process.Start(processInfo);
proc.ErrorDataReceived += (sender, errorLine) => { if (errorLine.Data != null) Trace.WriteLine(errorLine.Data); };
proc.OutputDataReceived += (sender, outputLine) => { if (outputLine.Data != null) Trace.WriteLine(outputLine.Data); };
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit();
Just waiting for each thread to end before updating the progress bar results in nothing happening ... then a quick jump .. 3 times. You may as well skip the progress bar.
The correct way to do it IMHO would be to calculate the toal work done across all 3 process:
totalwork = time1 + time2 + time3
Now, if you have multiple processors, it will take more like max(time1, time2, time3) but thats ok. It's a representation of work.
Have a shared variable for work-done. Each time a process does some more work, update the progress bar by calculating work-done += my-work-increment. The progress is just work-done/totalwork.
This will give good results regardless of whether the threads run sequentially or in parallel. Since you don't know how things are going to run (you might have a single processor cpu) this is the best approach.
Just create several instances of the Process class by calling the constructor, set the properties to redirect output stream, and then start them.
Your program won't wait for the called process to exit, as long as you don't call the WaitForExit method. No multi-threading is required.
Create a single thread.
In that thread (pseudocode):
Thread begins here
for each externalApp
Run the application with redirect output
Wait for exit
Update progress bar
end for
Thread ends here
See http://msdn.microsoft.com/en-us/library/ty0d8k56.aspx for wait for exit
Or... do you want to run the external apps in parallel?
Edit: based on the latest updates in the orginal post:
If you don't know the actual progress then don't use a regular progress bar. How about an infinite progress bar or a "working" icon?
An infinite progress bar could be a progress bar that fills up and the starts from beginning until everything is done. A working icon is like the Windows busy cursor (the ever spinning circle).
How about creating an ObservableCollection of TaskProgressInfo,
where TaskProgressInfo is a custom class, to which you write your progress.
Bind a WPF listview to that collection, using a datatemplate (with target type = TaskProgressInfo) to show a progressbar for each item (task).
Create an array of BackgroundWorkers that launch the external app and monitor it.
Each background worker should update its TaskProgressInfo, thus updating the datasource of a progressbar.
Upon completion each BackgroundWorker should remove its TaskProgressInfo from the ObservableCollection, thus removing a progress bar from the UI.
Since BackgroundWorker uses the background (UI) thread for report progress and completion,
the changes to the ObservableCollection will be done by its creating thread (thread safe).
Behind the scenes, .NET will use a ThreadPool - some backgroundworkers will share threads.
The following code does not exit the application. How can I exit the application and make sure all the running threads are closed?
foreach (Form form in Application.OpenForms)
{
form.Close();
}
Application.Exit();
You don't show the use of any threads in your code, but let's suppose you do have threads in it. To close all your threads you should set all of them to background threads before you start them, then they will be closed automatically when the application exits, e.g.:
Thread myThread = new Thread(...);
myThread.IsBackground = true; // <-- Set your thread to background
myThread.Start(...);
A "HOWTO: Stop Multiple Threads" article from microsoft: http://msdn.microsoft.com/en-us/library/aa457093.aspx
You can try the following code:
Environment.Exit(Environment.ExitCode);
I went through a similar issue in my software, but unfortunately just making the threads to work in background didn't solve the issue. In fact while the thread brings back data (the main software is data driven) and if I close the application, it results to Windows Error, giving rise to a debugging message.
So what actually worked for me:
Step 1: Made all threads run in background such as
Thread aThread = new Thread(MethodName);
aThread.IsBackground = true; //<-- Set the thread to work in background
aThread.Start();
Step 2: In the closing action of the form/application call the Environment.Exit method, such as
Environment.Exit(Environment.ExitCode);
This kept the memory managed perfectly, with no memory leak.
Hope this helps.
This should work for all threads you opened.
protected override void OnExiting(Object sender, EventArgs args)
{
base.OnExiting(sender, args);
Environment.Exit(Environment.ExitCode);
}
This is the best way to make sure that your application closes (forcefully):
(Process.GetCurrentProcess()).Kill()
The problem with Environment.Exit is that it does not work unless it is on the main thread. Also, it sometimes thread locks.
The main reason that your program is not closing properly is because the form is not able to dispose itself (and thus all object that it created). Fixing this is much more difficult. I would recommend running the above code after waiting a while for any possible dispose handlers to get called first.
This got the job done for me:
Instead of using:
Application.Exit()
which leaves other threads open, try using:
Environment.Exit(Environment.ExitCode);
I puzzled with this for a while as the common answer is to make the threads you call mythread.IsBackground = true;
The common answer to run a thread is to use a while loop with a flag
while(!exitflag)
{
// thread running
}
When User presses the eXit forms button Visual studio still is running the threads but the form closes. I used the Form Closing event to set the exitcode flag and then wait for the threads to close.
I have a single form using a Timer and two additional threads, One collects streaming data and the other does calculations on that data and saves to an sql table. Data collection is collected in a circular buffer. I use two static bool values as flags where the threads set the flag to true or false using mythread.Isalive as the Form Closing event does not have access to the thread handles.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Debug.WriteLine("Form Closing Event");
exitFlag = true;
int ThreadsClosed = 0;
while (ThreadsClosed < 2)
{
ThreadsClosed = 2;
if (ProcessDataAlive) ThreadsClosed = 0;
if (StreamingDataAlive) ThreadsClosed = 0;
Application.DoEvents();
}
Debug.WriteLine("Threads are all closed");
Thread.Sleep(5000); // allow debug window open to read remove for release
}