Is it possible to call ShowDialog(), but to create dialog window under main form, not on the top?
I'm calling ShowDialog because I want to stop executing the main program.
I don't need the dialog window, because I will create many dialogs from threads and they will prevent each other.
You need to read synchronization of threads. For stopping executing code use EventWaitHandle object.
Instead of creating and show dialog call WaitOne() of EventWaitHandle:
private static EventWaitHandle ev;
//...
[MTAThread]
public static void Main()
{
//...
ev = new EventWaitHandle(false, EventResetMode.ManualReset);
//...
ev.WaitOne(); //Stop execution
//...
}
//Another thread function.
public static void ThreadProc()
{
//...
ev.Set(); //Continue execution of Main
//...
}
A good example is on MSDN. Also note, that you need to call Reset() before using blocking again or create EventWaitHandle with EventResetMode.AutoReset option (read more on MSDN).
Related
Can anyone give me a headstart on the topic of threading? I think I know how to do a few things but I need to know how to do the following:
Setup a main thread that will stay active until I signal it to stop(in case you wonder, it will terminate when data is received). Then i want a second thread to start which will capture data from a textbox and should quit when I signal it to that of which occurs when the user presses the enter key.
Cheers!
This is how I do it...
public class ThreadA {
public ThreadA(object[] args) {
...
}
public void Run() {
while (true) {
Thread.sleep(1000); // wait 1 second for something to happen.
doStuff();
if(conditionToExitReceived) // what im waiting for...
break;
}
//perform cleanup if there is any...
}
}
Then to run this in its own thread... ( I do it this way because I also want to send args to the thread)
private void FireThread(){
Thread thread = new Thread(new ThreadStart(this.startThread));
thread.start();
}
private void (startThread){
new ThreadA(args).Run();
}
The thread is created by calling "FireThread()"
The newly created thread will run until its condition to stop is met, then it dies...
You can signal the "main" with delegates, to tell it when the thread has died.. so you can then start the second one...
Best to read through : This MSDN Article
Thread th = new Thread(function1);
th.Start();
th.Abort();
void function1(){
//code here
}
Use a static AutoResetEvent in your spawned threads to call back to the main thread using the Set() method. This guy has a fairly good demo in SO on how to use it.
AutoResetEvent clarification
I faced with one interesting moment when working with multithreading.
I have two threads. In main thread I create layout and add to it control,in second thread I create another control and add to the same layout. It works fine, but second thread works a bit longer then main. So main should wait for second thread.I use for this AutoResetEvent and got DeadLock. Below I describe code what I use:
private static AutoResetEvent resetEvent = new AutoResetEvent(false);
private BackgroundWorker backgroundAdvancedViewWorker = new BackgroundWorker();
private delegate void ShowViewDelegate();
public void Run()
{
MainGeneralReportForm mainForm = ObjectFactory.GetOrCreateView<IMainGeneralReportForm>();
backgroundSimpleViewWorker.RunWorkerAsync(_mainForm);
GeneralReportFormatView formatView =
ObjectFactory.ShowView<IGeneralReportFormatView>()
resetEvent.WaitOne();
DoSomething(advancedSearchView);
}
private void backgroundAdvancedViewWorker_DoWork(object sender, DoWorkEventArgs e)
{
MainGeneralReportForm mainForm = e.Argument as MainGeneralReportForm;
if (mainForm!= null && mainForm.InvokeRequired)
{
mainForm.BeginInvoke(new ShowViewDelegate(() =>
{
advancedSearchView =
ObjectFactory.ShowView<IGeneralReportAdvancedSearchView>();
resetEvent.Set();
}));
}
}
}
If main thread doesn't wait for second thread, the application throws NullReferenceException.
Is exist any solution or workaround of this problem?
You block main thread by resetEvent.WaitOne(); and at the same time trying to schedule work item back to main thread with BeginInvoke (which indeed can't run as main thread is waiting).
Not sure what right fix would be, but blocking on main thread is not really an option.
Maybe some "state" field on the form may be enough. Or maybe running DoSomething(advancedSearchView); from BeginInvoke callback (instead of resetEvent.Set();).
Note: if you are on 4.5 you can consider using async/await instead of manual threading.
I have an issue that relates to threading, cleaning up unmanaged resources and shutting down my app.
In the main UI thread I have a method that creates a new instance of class Worker. In Worker's constructor I start a new thread that has a while(Scanning) loop that updates some controls in my UI using Invoke() continuously (until Scanning bool is set to false). In the UI thread I raise the event FormClosing() whenever the application is closing down (through X button or Application.Exit() etc.). In FormClosing() I set Scanning to false and do some cleanup of unmanaged resources (that can only be done after the worker thread is done, because it uses those resources. The problem is that when I close the app down the MainForm apparently gets instantly disposed, so the app crashes at the Invoke (because it is trying to make a delegate run from UI thread, but that thread is disposed).
In an attempt to make the worker finish before the UI closes I tried to create a method StopWorker() in the worker class where I put Scanning = false, and then Thread.Join. As you can imagine the Join caused a deadlock as it makes the UI thread sleep but the Invoke needs the UI thread to move on.
In summary I need to cleanup unmanaged resources in FormClosing. I need the worker thread to be done before I do that though, as it uses these resources. The worker thread cannot finish (it uses Invoke) if the MainForm is disposed, therefore creating a tricky situation.
Based on Hans Passant's answer here, I created the below solution. It seems to be working very well.
In UI class/thread:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
var button = sender as Button;
if (button != null && string.Equals(button.Name, #"CloseButton"))
{
//FormClosing event raised by a user-created button action
}
else
{
//FormClosing event raised by program or the X in top right corner
//Do cleanup work (stop threads and clean up unmanaged resources)
if (_bw.Scanning)
{
_bw.Scanning = false;
ClosePending = true;
e.Cancel = true;
return;
}
//Code to clean up unmanaged resources goes here (dummy code below)
ApplicationLogger.Get.Log("Doing final cleanup work and exiting application...");
MemoryHandler.Get.Dispose();
ApplicationLogger.Get.Dispose();
}
}
My worker thread is in another class that has a public bool property called Scanning. It also has this while loop (notice the line at the bottom):
private void Worker()
{
while (Scanning)
{
Thread.Sleep(50);
_sendBackValue[0] = "lbOne";
_sendBackValue[1] = "blaBla";
_synch.Invoke(_valueDelegate, _sendBackValue);
_sendBackValue[0] = "lbTwo";
_sendBackValue[1] = "blaBla";
_synch.Invoke(_valueDelegate, _sendBackValue);
_sendBackValue[0] = "lbThree";
_sendBackValue[1] = "blaBla";
_synch.Invoke(_valueDelegate, _sendBackValue);
}
MainForm.Get.Invoke((Action)(() => MainForm.Get.StopScanning()));
}
Finally, back in the UI class/thread I have this method:
public void StopScanning()
{
if (!ClosePending) return;
ApplicationLogger.Get.Log("Worker thread is closing the application...");
Close();
}
Could you not better use the BackgroundWorker class/control? It is much easier to use because it has already a lot of synchronization stuff in it.
But if you have a separate thread, in your FormClosing event, use:
yourThread.Abort();
yourThread.Join(); // or yourThread.Join(1000); where 1000 is some kind of time out value
in your thread use try-excpet-finally construct
try
{
// do your stuff
}
catch (ThreadAbortException)
{
// do someting when your thread is aborted
}
finally
{
// do the clean up. Don't let it take too long.
}
Note that the Join command will block further execution until the thread has stopped. Therefore, I would recommend a not too high value for the time out parameter, otherwise the user interface will be blocked and will irritate users.
Disclaimer: I do not advocate the use of Thread, ManualResetEvent and, above all, volatile in the .NET 4.5+ era, but since the .NET version was not specified I've done my best to address the problem while keeping things as backwards-compatible as possible.
Here's a solution which uses a polling variable and a ManualResetEvent to block the execution of the FormClosing handler until the loop has completed - without any deadlocks. In your scenario if you have a class-level reference to the Thread which runs the loop, you can use Thread.Join instead of ManualResetEvent.WaitOne in the FormClosing handler - the semantics will be the same.
using System;
using System.Threading;
using System.Windows.Forms;
namespace FormClosingExample
{
public partial class Form1 : Form
{
private volatile bool Scanning = true;
private readonly ManualResetEvent LoopFinishedMre = new ManualResetEvent(false);
private readonly SynchronizationContext UiContext;
public Form1()
{
this.InitializeComponent();
// Capture UI context.
this.UiContext = SynchronizationContext.Current;
// Spin up the worker thread.
new Thread(this.Loop).Start();
}
private void Loop()
{
int i = 0;
while (this.Scanning)
{
// Some operation on unmanaged resource.
i++;
// Asynchronous UI-bound action (progress reporting).
// We can't use Send here because it will deadlock if
// the call to WaitOne sneaks in between the Scanning
// check and sync context dispatch.
this.UiContext.Post(_ =>
{
// Note that it is possible that this will
// execute *after* Scanning is set to false
// (read: when the form has already closed),
// in which case the control *might* have
// already been disposed.
if (this.Scanning)
{
this.Text = i.ToString();
}
}, null);
// Artifical delay.
Thread.Sleep(1000);
}
// Tell the FormClosing handler that the
// loop has finished and it is safe to
// dispose of the unmanaged resource.
this.LoopFinishedMre.Set();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// Tell the worker that it needs
// to break out of the loop.
this.Scanning = false;
// Block UI thread until Loop() has finished.
this.LoopFinishedMre.WaitOne();
// The loop has finished. It is safe to do cleanup.
MessageBox.Show("It is now safe to dispose of the unmanaged resource.");
}
}
}
Now, while this solution is (somewhat) tailored to your description of the problem (which I interpreted to the best of my ability), I had to make a large number of assumptions. If you want a better answer, you'll need to post a concise repro of the problem - not necessarily your production code, but at least a trimmed down working version which still has all the main nuts and bolts in place and exhibits the problem you've described.
In my application I've created a thread which draws on a Bitmap object, and when it is done drawing it calls form.Invoke(form.Refresh) which draws the bitmap to the main form. (form being a reference to the main form of my application.)
The Problem: I've noticed that if I close the form while the other thread is waiting for the callback message from UI thread (because of the Invoke call) - the thread will wait indefinitely(?) and will essentially get stuck, preventing the application from closing.
Using BeginInvoke doesn't make sense in my program, because the time it takes to refresh the form has to be accounted for in the work of the thread.
Q: What would be the best way to prevent this from happening?
Edit: I've read in some places that its a bad idea, but it seems to me that the only way to deal with this is to call Thread.Abort(). I can't close the thread by using a flag or something similar, since its just stuck at the Invoke call.
Edit 2: To make it clear, what I'm looking for is a way to tell the worker thread that it should stop waiting for the Invoke callback and continue working.
The best answer is of course to use BeginInvoke. If you need the thread to wait until the UI thread has processed the result, then you'll have to add another synchronization method to the process.
An AutoResetEvent would work as a gate, something like this:
using System;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
public class MainForm : Form
{
protected override void OnLoad(EventArgs e)
{
new Thread(ProcessBitmap) { IsBackground = true }.Start(null);
base.OnLoad(e);
}
void DoneProcessingBitmap(Bitmap bitmap)
{
Trace.WriteLine("Done Processing Bitmap");
uiDoneEvent.Set();
}
AutoResetEvent uiDoneEvent = new AutoResetEvent(false);
volatile bool terminate = false;
void ProcessBitmap(object state)
{
while (!terminate)
{
Bitmap bitmap = (Bitmap)state;
Trace.WriteLine("Processing Bitmap");
Thread.Sleep(5000); // simulate processing
BeginInvoke(new Action<Bitmap>(DoneProcessingBitmap), bitmap);
Trace.WriteLine("Waiting");
uiDoneEvent.WaitOne();
}
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
Check if the form still exists before calling Invoke. Something like...
if (form != null && !form.Disposed)
form.Invoke(form.Refresh());
Monitor moni = new Monitor();
Thread t = new Thread(() => moni.CurrUsage(nics,200));
t.Start();
I start a thread named 't' inside the 'Form1_Load' function. I have added a button. When click on that button the thread 't' should stop executing and create a new thread with these parameters.
Monitor moni = new Monitor();
Thread t = new Thread(() => moni.CurrUsage(nics,950));
t.Start();
I know in the form_load event i can use the
t.Abort();
By making t a member of the form, you can reference it later on in the button-click event handler.
Graceful Abort.
Although t.Abort() gets the job done, you might be left with half-processed data in the thread t. You can catch the ThreadAbortException in thread t to gracefully end processing.
Beware of overlap.
The second problem is that your thread might not have aborted yet while your new thread has started already. You can prevent that by calling t.Join() after calling t.Abort().
Hope this helps.
Make Thread t a private member of your form.
public partial class MainForm : Form
{
private Thread t;
}
One way is to make Thread t a global variable (place outside of Form_Load). Then it can be accessed and modified from any method in that class.
To instantiate the thread, use t = new Thread(.....
Before aborting the thread, make sure it is not null.
You need to make the Thread object accessable in both places that you need to access it.
In this case, making it a private varaible would work.
e.g.
public class MyClass
{
private Thread MyThread
{
get;
set;
}
private void myfunc1()
{
MyThread = new Thread(() => moni.CurrUsage(nics,200));
MyThread.Start();
}
private void myfunc2()
{
MyThread.Abort();
// I really need to wait until this thread has stopped...
MyThread.Join();
}
}
Adding to the already given answers:
Note that .Join() will block your current (UI) thread, leaving your application unresponsive to the user.
Just as another take: avoid using .Abort() by using a flag in your Monitor class to exit the task you are doing if possible. You can then still wait for .Join(), but you have full control of the state in the background thread.
public class Monitor
{
private bool _cancel = false;
public void Cancel()
{
_cancel = true;
}
public void CurrUsage(Nics nics, int n)
{
_cancel = false;
// ...
while (!_cancel)
{
// do some stuff
}
}
}
in your Form
private Monitor _monitor { get; set; }
private Thread _t;
public void Button_Click(...)
{
_monitor.Cancel()
_t.Join() // will return as your background thread has finished cleanly
_t = new Thread(() => _monitor.CurrUsage(nics,950));
t.Start();
}
As others have pointed out, all you need in order to call Abort is a reference to the thread (just like any other object in .NET).
However
You should seriously consider rethinking this approach. In general, calling Abort is discouraged, as it does not give the target thread sufficient opportunity to reach a stopping point. While it's sometimes appropriate (or the only option), it's almost always a better idea to ask the target thread to stop (usually through a volatile bool rather than forcing it like this.
For example,
public class ThreadClass
{
private volatile bool stopRequested;
private Thread thread;
public void Start()
{
stopRequested = false;
thread = new Thread(ThreadMethod);
thread.Start();
}
public void Stop()
{
stopRequested = true;
if(!thread.Join(5000)) thread.Abort(); // forcefully abort if not
// completed within 5 seconds
}
private void ThreadMethod()
{
}
}
Your code then goes into ThreadMethod. Within the method, periodically check the value of stopRequested. If it's true, perform whatever cleanup is necessary (if any) and gracefully return out of the thread. If the content is a loop, the general practice is to place the check at the start of the loop (assuming that the loop is sufficiently tight) and exit early if the value is true. The exact placement is really dependent upon the code, but the general idea is that it should be checked often enough to make the thread exit fairly quickly after it gets set, regardless of when that happens.