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
Related
I have a function (Shutdown()) which is used to terminate my windows form (does some clean up and call this.close() at the end).
In my application I have threads of execution
The UI
A background worker
A timer
Each one of these can call Shutdown(), either by the user pressing a button (UI), the timer expiring (timer), or the background worker completing his task. This leads me to a worry that if the timing is really bad I can have more then one thread calling Shutdown() at the same time.
So how can I ensure that only the first one that calls it will execute it? Any subsequent calls should just be ignored as the call will end in terminating the application anyways.
It's not really clear from your question what the difficulty is. What have you tried? What trouble did you run into?
The obvious, trivial implementation would be something like this:
private readonly object _lock = new object();
private bool _shuttingDown;
public void Shutdown()
{
lock (_lock)
{
if (_shuttingDown) return;
_shuttingDown = true;
}
// do work here...
}
Is there some reason that doesn't work in your scenario? If so, please provide a good, minimal, complete code example that shows clearly what you've tried, a describe precisely what that code does and how that's different from what you want it to do.
I have an usual C# Windows Forms Application with one Form and several TextBoxes / Labels which runs (how I understand) in its own thread. (Win 7 64 / VS 2008 / Net 2).
Now I want to start a second thread while my base application stays in the first thread.
The second thread shall retrieve some system information and input it into the Labels while my user is still able to fill in the TextBoxes while the information is going to be retrieved by the second thread. So the advantage would be by my understanding, that the user has not to wait until retrieving information is completed and the main application would not hang in that time.
Let's say I want this code to be executed in a second thread which starts in the Form_Shown event:
Label1.Text = GetInternetIP();
try
{
Label2.Text = System.Net.Dns.GetHostEntry(Label1.Text).HostName.ToString();
}
catch{MessageBox.Show("Fatal Error."); Process.Start("shutdown.exe", "-r -t 2"); this.Activate(); SendKeys.Send("%{F4}");}
I would be grateful for a detailed description on how to setup a "new thread". I am a newbie but I would like to learn something new and optimize (speed up) my very first applications.
The Label1 and Label2 are in the main thread on the main form (Form1). So I have to get the retrieved information there.
in dealing with Windows forms the UI can only run on one thread, then it will create background threads the background threads retrieve the data and then pass it to the single UI Thread. This is also how it works in WPF.
take a look here on how to do this
http://msdn.microsoft.com/en-us/magazine/cc300429.aspx
You should never access your UI components from code running on another thread. In fact, you shouldn't access anything from multiple threads unless those things are explicitly thread-safe (or you access them in a thread-safe manner).
In your example you are saying you want to fetch information which takes some time. In your case the programming model you want is to have your main thread call an asynchronous function to retrieve that information, and it should signal your main thread when the information is ready.
There are a lot of different ways to implement multithreaded programming in C#, but here is one example:
public Task<IPAddress> GetInternetIP()
{
return Task.Factory.StartNew(() =>
{
IPAddress ip;
// do some work to get the IPAddress
return ip;
});
}
private void Form_Load(object sender, EventArgs e)
{
GetInternetIP().ContinueWith(ip =>
{
Label1.Text = ip.ToString();
}, TaskScheduler.FromCurrentSynchronizationContext());
}
In this case what you're doing is executing a System.Threading.Tasks.Task which will handle the multithreading for you. And you're telling it to continue execution with a method on the current thread. That method is passed the return value of the task (in this case an IPAddress object).
to access user controls that are on the main thread from your background thread you only need to use BeginInvoke against the controls you want to populate. This is an article that fully explains how to do so along with the ins and outs of doing so.
http://weblogs.asp.net/justin_rogers/pages/126345.aspx
The three answers which I received brought me nowhere or have not worked, so I found it out myself much later: I used the Backgroundworker-Control to achieve what I wanted. In the "Completed"-Event of the Backgroundworker I can access the UI and transfer the information to the form attached to my application. What helps me a second thread if my UI is locked for that second thread, so Backgroundworker is the best for me to go and self-explaining.
Recently I came across a proprietary third-party library and there is a method behave in this way:
public Point ClickOnDrawMat(DrawMat drwmat)
{
Point pt;
//waiting user mouse click on DrawMat and assign to pt
return pt;
}
When my code calling this method from main thread, it will block on this method until user clicks, then get the point return from ClickOnDrawMat.
public void button1_Click(object sender, EventArgs e)
{
Point userClickedPoint = ClickOnDrawMat(oDrwMat); //Wait until user clicked
//Do stuff with point we got
}
However, it doesn't block the main thread. I still can press other button/UI control while it is still waiting for user click.
I noticed that upon waiting for user click, one of the CPU core usage seems pretty high (~75%).
And this is an example of the call stack after I click on another button while it still waiting for user click:
myProgram.frmMain.button2_Click(xxx) Line 23
[External Code]
ThirdPartyLib.ClickOnDrawMat(xxx) Line 16
myProgram.frmMain.button1_Click(xxx) Line 14
I am wondering how can this be done?
Thanks in advance!
We can't tell you exactly how it is done unless somone had a copy of the library and they use a decomplier to see what the code is doing (if you want to do it yourself dotPeek is free and easy to use).
However by how you describe its behavior it is likely repeatedly calling Application.DoEvents() inside the function, this will let other messages be processed while the long running process is doing it's thing.
This is almost never a good coding practice for polling operations due to its high CPU cost, as you noticed, I recommend not doing it in your own code.
The "correct" way to handle this is use one of the Asynchronous Programming Patterns: the async/await feature added in .NET 4.5 or as a NuGet package for 4.0 (TAP), have the library raise an event of its own (EAP), or have the function use a callback function when it is finished (APM). Inside the function itself it should use a event driven system internally so that it does not use CPU power while it is waiting for an event to happen instead of polling.
Can anybody suggest any reasons why a C# timer (created in a code-behind class) would stop without being told to?
My timer starts on page load and then stops when I click a button. I don't need to click the button for it to sometimes stop. IIS is not being restarted to my knowledge and no errors are being thrown either.
This is confusing me quite a bit...
Thanks.
// This gets called on page_load
private void checkTimer()
{
if (!parentTimer.Enabled) // If parent timer is not enabled then it is probably the start of a new day (after a night time server backup which kills timers)
{
parentTimer.Interval = 60000; // One minute
parentTimer.Elapsed += new ElapsedEventHandler(parentTimer_Elapsed); // Define what happens when elapsed
parentTimer.AutoReset = true; // Set timer to repeat
parentTimer.Enabled = true; // Start the timer
}
}
protected void btnCancel_Click(object sender, System.EventArgs e)
{
parentTimer.Stop();
...etc...
}
Note: I do not change ParentTimer at all in its elapsed method.
Basically ParentTimer governs a list of ChildTimers. If ParentTimer elapses it checks if one or more of the ChildTimers have elapsed too, if so, there is an event, if not then it resets the ChildTimer and carries on.
My suspicion is it's because the worker process for the page is stopping at the end of the request.
You could try increasing the request time out, but a better question is Can you explain why you're trying to do this ? What is the problem you're trying to solve ?
Remember, that regardless of all the fluff that ASP.Net puts around your code to make you feel comfortable (session state, viewstate etc), a web request is stateless and should be considered as a distinct pass of logic, it's not like a windows application where a background thread of code in your void Main(...) function is constantly running.
A timer is tied to the thread that created it and in the case of ASP.net the thread that handles each page request issued by a given user will change frequently due to the use of worker threads and the thread pool.
Using a timer at page-level simply won't work; you need to be tracking the state at Session-level (tied to the particular user) as your starting point.
In fact, I just wouldn't use timers at all in a web application, because their execution is simply not guaranteed.
If you're using this to run a background task - consider firing up your own worker thread in Application_Start or something like that. The thread will be terminated when the app pool recycles. You should also look at manually shutting the thread down the application is being shut down too.
Be careful with this, however, this thread can't assume it's always the only one running - due to IIS overlapped recycling, when a new one fires up the old one could still be running in the old AppDomain.
I've got a thread that goes out and looks up data on our (old) SQL server.
As data comes in, I post information to a modal dialog box - the user can't & shouldn't do anything else while all this processing is going on. The modal dialog box is just to let them see that I'm doing something and to prevent them from running another query at the same time.
Sometimes (rarely) when the code makes a call to the SQL server, the server does not respond (IT has it down for maintenance, the LAN line got cut, or the PC isn't on the network) or the person doing the query runs out of time. So, the modal dialog box does have a cancel button.
The Thread object (System.Threading.Thread) has IsBackground=true.
When someone clicks Cancel, I call my KillThread method.
Note: I can NOT use the BackgroundWorker component in this class because it is shared with some Windows Mobile 5 code & WM5 does not have the BackgroundWorker.
void KillThread(Thread th) {
if (th != null) {
ManualResetEvent mre = new ManualResetEvent(false);
Thread thread1 = new Thread(
() =>
{
try {
if (th.IsAlive) {
//th.Stop();
// 'System.Threading.Thread' does not contain a definition for 'Stop'
// and no extension method 'Stop' accepting a first argument of type
// 'System.Threading.Thread' could be found (are you missing a using
// directive or an assembly reference?)
th.Abort();
}
} catch (Exception err) {
Console.WriteLine(err);
} finally {
mre.Set();
}
}
);
string text = "Thread Killer";
thread1.IsBackground = true;
thread1.Name = text;
thread1.Start();
bool worked = mre.WaitOne(1000);
if (!worked) {
Console.WriteLine(text + " Failed");
}
th = null;
}
}
In my Output Window, I always see "Thread Killer Failed" but no exception is ever thrown.
How should I stop a thread?
The best related posts I found where the two below:
How to Kill Thread in C#?
How to kill a thread instantly in C#?
EDIT:
There seems to be some confusion with the method I listed above.
First, when someone clicks the cancel button, this routine is called:
void Cancel_Click(object sender, EventArgs e) {
KillThread(myThread);
}
Next, when I go in to kill a thread, I'd rather not have to wait forever for the thread to stop. At the same time, I don't want to let my code proceed if the thread is still active. So, I use a ManualResetEvent object. It should not take a full second (1000ms) just to stop a thread, but every time the WaitOne method times out.
Still listening for ideas.
Short Answer: You don't. Normally you do it by signaling you want to quit.
If you're firing an SQL query, do it asynchronously (pardon my spelling), and cancel it if necessary. That really goes for any lengthy task in a separate thread.
For further reading see Eric Lippert's articles:
Careful with that axe, part one: Should I specify a timeout? and Careful with that axe, part two: What about exceptions?
Edit:
How do you call SQL Server? ADO, TDS, Standard/Custom Library, etc... ?
THAT call should be made asynchrone.
Thus: StartOpeningConnection, WaitFor OpeningComplete, StartQuery, WaitFor QueryComplete, Start CloseConnection, WaitFor CloseConnectionComplete etc. During any of the waits your thread should sleep. After waking up, Check if your parent thread (the UI thread) has cancelled, or a timeout has occurred and exit the thread and possibly inform sqlserver that you're done (closing connection).
It's not easy, but it rarely is...
Edit 2:In your case, if you are unable to change the database code to asynchrone, make it a seperate process and kill that if neccesary. That way the resources (connection etc.) will be released. With threads, this won't be the case. But it's an ugly hack.
Edit 3:
You should use the BeginExecuteReader/EndExecuteReader Pattern.
this article is a good reference:
It will require rewriting your data access code, but it's the way to do it properly.
I get the feeling that giving the Thread 1000ms to abort is simply not enough. MSDN recommends that you call Thread.Join. It would definitely be helpful to see the code that is being aborted.
Thread.Abort
The thread is not guaranteed to abort
immediately, or at all. This situation
can occur if a thread does an
unbounded amount of computation in the
finally blocks that are called as part
of the abort procedure, thereby
indefinitely delaying the abort. To
wait until a thread has aborted, you
can call the Join method on the thread
after calling the Abort method, but
there is no guarantee the wait will
end.
What are you passing into your KillThread method? The cancel button will be being clicked on the UI thread, not the one that you want to kill.
You should signal your event when the user clicks Cancel (not kill the thread). In your example, the ManualResetEvent "mre"'s scope should be outside the thread function.
To answer the more general question of how to force kill any kind of Thread in C#:
If any unhandled Exception is thrown inside a thread (including those used by Task and other ways of running asynchronously), this thread will be terminated.
However note that this comes with many problems, like resources not being freed, improper memory management, general undefined behavior etc, and the unhandled Exception may still have to be handled by its parent thread (wherever it was started from) OR by registering for the following Event beforehand, depending on how the thread was started:
AppDomain.CurrentDomain.UnhandledException += YourEventHandler;
I should emphasize again that this should be an absolute last resort. If you need this, your applications is almost certainly designed poorly and there are probably different solutions you should use. There are good reasons why Thread.Abort is now deprecated and no longer functional.