Interthread communication - Manual Reset Event - c#

I am trying to establish a pause and play communication between threads.I am spawning two threads for two forms at the startup, one is the mainthread which is for mainwindow and second thread of form2,
var thread = new Thread(ThreadStart);
thread.TrySetApartmentState(ApartmentState.STA);
thread.Start();
private static void ThreadStart()
{
Application.Run(new SecondForm()); // other form started on its own UI thread
}
Mainwindow has a button on clicking which multiple threads would be spawn for different operations - it executes without pause until the intended jobs are complete.
In the second form I have two buttons stop, and start clicking on which I should be able to stop and start the mainwindow(All the child threads).
For this I am declaring
public static ManualResetEvent mre = new ManualResetEvent(false);
in program.cs where two UI threads are started
and trying to invoke it from the second form on start and stop
private void btnStop_Click(object sender, EventArgs e)
{
Invoke((MethodInvoker) delegate
{
Program.mre.WaitOne();
});
}
private void btnStart_Click(object sender, EventArgs e)
{
Invoke((MethodInvoker) delegate
{
Program.mre.Set();
});
}
Once I click the button on mainwindow which continues with series of operations I try to click on STOP button in secondform, this disables the second form, and the operation from the mainwindow continues, please let me know where I am going wrong.

Other than the fact that this is a completely silly threading design, there's two issues:
You Invoke on the second form, so you're blocking its messaging loop. Instead, you would want to do mainWindow.Invoke( ... ).
Even that will not help you when main window spawns worker threads. It will only stop the form's message loop, not the threads it has already spawned.

I found a solution to the problem. When I click on Pause button I am setting a bool say continue to false, and using this variable in a loop where actual calls to function is done.
In the same class where I have my loop I have the manual reset event initialized, when continue is false I am calling mre.WaitOne(), which would pause the current thread from execution without causing any harm to other threads.
When Play is clicked I am Setting the Manual Reset event object which would restart the thread.

Related

Stop thread from any form or thread

I have a application that adds items queried from SQL into a list box on my main WPF form. The query takes a long time so I added it to its own thread. I have another thread that shows a new form with a please wait gif animation on it.
So in total I have 3 threads.
Main GUI thread
Thread running SQL query - thread named sql_thread
Thread opens/shows new instance of please wait form with Gif animation on it. - thread name please_wait_thread
I want the ability to cancel the thread running the SQL query from a cancel button on the please_wait_thread that shows a form with a please wait Gif animation.
I am having a real hard time understanding inheritance and how to reference objects between forms. I know how to create new instances of them but not make them communicate.
If I put the below code in the please_wait form and type sql_thread it cannot see the sql thread.
public void Cancel_btn_Click(object sender, EventArgs e)
{
sql_thread.abort();
}
How can I stop the sql_thread in it's tracks when I close the please_wait form?
The code to create the sql_thread on the main form is below.
private void btn_search_Click(object sender, EventArgs e)
{
Thread sql_thread = new Thread(sql_search_method);
}
P.S. I already tried a backgroundworker but it did not work and once it hits the long query there is no way to stop it until its done with a backgroundworker.

How can I stop a long-running subroutine in my Form with a Button?

I have a Console app that displays a WinForms Form.
In the Form, the user clicks button 1 and it runs a long subroutine. I want to have a button 2 that can kill the subroutine at any point. However, the UI freezes when I click button 1 until the subroutine has finished. How can I get the UI to not freeze?
Your long-running code is blocking the UI thread, so you can no longer click the second button, nor interact with the UI in any way until the code is finished executing.
You'll need to move your long-running code to a separate thread. There are various (and newer) ways of doing this, but one way is the BackgroundWorker. It's pretty easy to learn, and wraps some nice functionality, like cancelling the thread.
Here's a short WinForms app to demonstrate. You have to explicitly enable the ability for the thread to be cancelled. In this example, the while loop continues indefinitely, but checks every 100ms to see if there's a request for it to be cancelled. When you click the second button, the cancellation request is sent, and the thread ends.
public partial class Form1 : Form
{
private BackgroundWorker bg;
public Form1()
{
InitializeComponent();
bg = new BackgroundWorker
{
WorkerSupportsCancellation = true
};
bg.DoWork += (sender, args) =>
{
while (true)
{
Thread.Sleep(100);
if (bg.CancellationPending)
break;
}
MessageBox.Show("Done!");
};
}
private void button1_Click(object sender, EventArgs e)
{
bg.RunWorkerAsync();
}
private void button2_Click(object sender, EventArgs e)
{
bg.CancelAsync();
}
}
Following up on chouaib's comment, another nice thing about using the BackgroundWorker in a WinForms environment is that you can drop and drop it onto your designer, similar to a Menu, Timer, etc. You can then access its members in the "properties" panel, setting "WorkerSupportsCancellation" to true, subscribing to events, etc.
From your comment:
"is there a way to run this background process and be able to update the main userform? I keep getting the "cross-thread operation not valid control accessed from a thread other than the..." I want to run the long-running background operation, and have it update the main UI with text in a label (like a percentage of its progress)"
If you want to update the UI while the thread is running, you should do that from the ProgressChanged event. First, enable that option and subscribe to the event:
bg.WorkerReportsProgress = true;
bg.ProgressChanged += bg_ProgressChanged;
Then call ReportProgress() when you want to update the UI. You could pass back a percentage complete and some text, for instance:
bg.ReportProgress(50, "Almost there...");
Finally, update the UI from inside the event:
void bg_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var message = e.UserState.ToString();
var percent = e.ProgressPercentage;
lblStatus.Text = message + " " + percent;
}
You need to make it multithreaded as suggested in the comments. The older way of doing this was manage your own thread. Then along came the background worker (cheap and easy). Now a days you have other options such as the Task Library.
Remember - anything the runs on the UI thread prevents the UI from sending and receiving events until that operation is finished.
Look into the BackgroundWorker component

Allow user to click on a Button of the form when Application is in Pause/Sleep Mode in C# winform Application

I am working on a C# winform application which continuously navigates some links in a webbrowser control and process the data of that webpage. I need to provide two buttons on the form for Pause and Resume.
On click of button the whole application should get pause processing and after that on click of Resume button it should start again.
So to pause the application, on click of Pause button I made thread to sleep for infinite time by following code.
private void Pause_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
}
But this piece of code unable the user to click on Resume Button on form to resume the application. Also I am not getting a perfect piece of code to resume the application on click of Resume Button.
Can Anyone get me the correct solution for this issue ?
Thread.Sleep method yields execution of code to process scheduler and doesn't get it back until specified time passes. Therefore you can't make sleeping thread wake itself up. You can't even make a working thread wake another sleeping thread (to my knowledge).
You need to accomplish your goal differently.
Separate data processing code to separate, worker, method
Run worker method in separate thread
Share a state variable between UI and worker thread. This variable should pass signals on whether execution should be paused.
From UI thread, set pause signals in shared variable as needed
In processing loop, write handler code for stopping processing
I'll post some pseudo code below on how you should do this:
private bool _Paused = false;
private void OnPauseClick()
{
_Paused = true;
}
private void OnResumeClick()
{
_Paused = false;
}
private void OnRunClick()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(WorkerMethod));
}
private void WorkerMethod(object state)
{
...
while (needToDoMoreWork)
{
// do some work here
...
// if pause requested, wait to unpause
while (_Paused)
{
// Sleep for a short time and check again if paused
Thread.Sleep(100);
}
}
}
You'll need to fill in the blanks according to your business needs.
If you put your UI thread to indefinite sleep, you're going to kill your UI indefinitely. Don't do that.
Your application has some mechanism to know it's time to do its navigation and processing, probably a timer of some sort. If it's a timer, just stop it when you pause the application, and start it again when you resume. If it's some other mechanism, you need to stop it,too, but it's hard to tell you how without knowing what that mechanism is.

C# WinForms: activating a timer from a thread

public void timer_thing()
{
Thread timer = new Thread(new ThreadStart(() =>
{
Thread.Sleep(500);
if (is_mouse_down)
timer1.Enabled = true;
}
));
timer.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
//some stuff happens here
}
As you can see I want the thread to activate the timer. But the timer doesn't activate. I guess this is not the right way. Or i'm missing something.
It could be that is_mouse_down is false whenever the thread hits that instruction. The thread is not going to magically wait for it to turn true.
However, you have another, bigger problem to worry about. The thing is you cannot touch any UI element from a worker thread or any other other than the UI thread. This includes the System.Windows.Forms.Timer. All sorts of undefined chaos may ensue. Your application may fail unpredictably and spectacularly.
It is not really clear to me why a thread is needed in the first place. Can you not handle the Control.MouseDown event and enable the timer in the event handler for that event? That is how I would solve the problem.
Your thread isn't waiting for the is_mouse_down event. It just checks after half a second and if it's not the time won't get enabled and the tread closes. Maybe you should try using an event?
You can use AutoResetEvent to automatically trigger it from Button Click handler.
So in thread just set:
autoResetEvent.WaitOne();
timer1.Enabled = true;
and in button click handler:
autoResetEvent.Set();
BTW, why you can not initialize a Timer in the Click handler?
This problem as described in literature has two solutions:
1) Active waiting
2) Notifications
If you want the active waiting solution(which is really an outdated one, your thread should have while loop).
If you want the notification when you should call some method which starts the timer in the mouse down event handler
If you have questions about c# multithreading you should read this article. It is really helpful and will show you AutoresetEvent, ManualResetEvents, Thread Timers, Timers, etc. Really good general article.
You have to pass the timer1_Tick callback when you declare your timer object.

I can only close a form once, InvalidOperation Exception Invoke or BeginInvoke cannot be called on a control until the window handle has been created

Hi
I'm opening a form like this from my main form when the user makes a selection of a menu item.
private void commToolStripMenuItem_Click(object sender, EventArgs e)
{
Command_Form Command_Form1 = new Command_Form();
Command_Form1.ShowDialog();
// Command_Form1.Dispose(); this didn't help
}
Inside the form "Command_Form1"
I close it like this when the user clicks on the close button
private void Close_button_Click(object sender, EventArgs e)
{
this.Close(); //I get the exception here
}
This process works fine once but on the second closing of the form
(Which I hope is a completely different/new instance of the form) I get the error in the title of this post.
This is the output in the debug window.
A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll
All the topics that list this error go on about not trying to do anything to a form that has not been displayed but this happens when I click on a button in the form.
It would seem to me that pretty much ensures the form has been displayed if I'm able to click its button.
The other posts I've found that list this type of error go on about making thread safe calls so I tried this as an experiment but it didn't make any difference.
private void Close_button_Click(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
CloseCallback d = new CloseCallback(Close_button_Click);
Invoke(d, new object[] { sender, e });
}
else
{
this.Close();
I have multiple threads in my application but they are created by the controls I'm using not by me explicitly.
I am passing data from a serial port to/from the form by Marshling the received/sent data via a delegate[s].
It makes sense that the serial port would run on a different thread than the form but why would a button click on a form be in a diffrent thread than the form????
The whole thread thing is very confuzing
How do I figure out what threads originated where and what is going on in the threads that I didn't create explicitly?
Why would I need to invoke the form's close method via a delegate?
Heck is there anything I can do in this multi threading environment that is thread safe How in do I know if what I'm doing is unsafe/safe if I don't know what/where/why/who/when is creating threads?
My guess is your close() call is not throwing that exception, but something that happens after close(). Have you stepped into the code with the debugger to see when it is fired?
As to when you need to invoke...There is only one thread allowed to make changes and access dynamic properties on the GUI, call it the GUI thread. The GUI thread is responsible for updating layout, firing events like buttons, etc. If you ever access the GUI from another thread (like a timer event) you need to use invoke() to queue your function to be run on the GUI thread. BeginInvoke will also queue the function but is asynchronous (will only queue the function to be run on GUI thread, but will not wait for it to finish).
Close_button_click will only be called by your gui thread when the button click event fires(unless you explicitly call it somewhere else in your code behind, not recommended!), so invokeRequired=false in your code above, and the invoke code is never executed.

Categories

Resources