Enable button clicking while another process is running - c#

I look trough google a bit but cant make it work.
I have some process done when i push a button.
I want to add a "Kill All" button to terrminate everying when pushed, but when i start a process i cant push any other button untill its finnished.
private void button_checkZero_phones_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(WorkThreadFunction));
thread.Start();
}
private void button_kill_all_Click(object sender, EventArgs e)
{
System.Environment.Exit(1);
}

You have to run your "Kill All" method in an async method. The main thread is always blocked when you run a long process.
More info about your problem:
WinForm Application UI Hangs during Long-Running Operation
Just use one of the following methods - run Kill All in:
A BackgroundWorker
Another thread
Another task
Use async/await
Reactive extensions
There are a several ways to notify you that the all processes are terminated! It depends on which method you use.

Use async funcations. I found these useful links
http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx
http://msdn.microsoft.com/en-us/library/vstudio/hh156513.aspx

Is this a Windows app? If you're feeling old-school and enjoy winding up other developers, stick an Application.DoEvents() in your loop of death.
You know you want to.
Of if you want to do it without receiving scorn from all your peers, see this question and answer.

Related

Thread.Sleep() doesn't work with Cv2.ImShow, OpenCvSharp, C#

Very Simple C# Winforms App, OpenCVSharp4, Thread.Sleep() doesn't work.
It seems like (as I guess) Cv2 cannot be used in multiple threads, eg, one thread create NamedWindow, another thread ImShow. But this simple code below is still confusing.
private void button1_Click(object sender, EventArgs e)
{
VideoCapture video = new VideoCapture("E:/RankingBack.mp4");
Mat frame = new Mat();
while (true)
{
video.Read(frame);
Cv2.ImShow(" ", frame);
//Cv2.WaitKey(33); // WORKS
Thread.Sleep(33); // DOES NOT WORK
}
frame.Dispose();
video.Release();
Cv2.DestroyAllWindows();
}
waitKey's purpose is not waiting, it's to spin the GUI event loop that OpenCV uses. If you don't call it, OpenCV's GUI doesn't work.
You're using C# and WinForms already (judging by the tags), so you should use WinForms instead of imshow. OpenCV does its own GUI event handling, which may conflict with other GUI toolkits that are being used in the same program.
OpenCV's GUI functions are generally not safe to call from threads because some GUI backends don't allow that. That's irrelevant though because...
You do not have a "thread" here. You have the handler for a button click event. That's executed by the event loop of your WinForms application. That happens in the main thread that is always there in every process. That is not a spawned thread.

termination of multiple background workers

I have a main thread that invokes multiple backgroundworkers (in .net/c#).
Each of these threads starts a process in order to run an executable.
When a process ends, I want to tell the main thread to kill all other threads and their respective processes. After all of them stopped, I want to know this and continue to run the main thread for post-processing.
I keep a list of these external processes so I have no problem killing them all. My problem is how to kill all these backgroundworkers. I tried to keep a list of the threads associated with them and kill them from within the first thread that terminates, but apparently this does not kill the backgroundworker itself because the runworkercompleted method is still invoked multiple times.
Does anyone have a pattern on how to kill those workers in a nice way ? should I somehow notify the main thread to do the killing of the other workers ?
I'd recommend using async/await and CancellationTokenSources. I'll give advice on how to use BackgroundWorkers as well, but since async/await is so much more convenient (and shorter), it goes first.
async/await is convenient because it gives you the features you're looking for without much added complexity.
private async void SomeEvent(object sender, EventArgs e)
{
CancellationTokenSource cts = new CancellationTokenSource();
var waiter1 = DoSomething(cts.Token);
var waiter2 = DoSomethingElse(cts.Token);
// etc.
// Wait for the first one to finish, then cancel
await Task.WhenAny(waiter1, waiter2, ...).ConfigureAwait(false);
cts.Cancel();
// wait for the remainder to finish
await Task.WhenAll(waiter1, waiter2, ...).ConfigureAwait(false);
// Do Postprocessing
}
Your "waiters" look something like this:
private async Task DoSomething(CancellationToken token)
{
// Do stuff
// Periodically check if someone has finished
if (Token.IsCancellationRequested)
{
// clean up
return;
}
}
async/await code has a few gotchas, including deadlock. Since this sounds like a quick project (I could be wrong), it seems like a good place to learn - especially if there's no massive codebase to rework. If you want to learn more, I think Stephen Cleary's blog is a good place to start, particularly his intro.
On the other hand, if you're absolutely sure you want to use BackgroundWorkers... well I don't blame you, but I don't envy you either.
First, your workers have to know whether somebody else finished first. Use the finished BackgroundWorker's RunWorkerCompleted method to cancel the others BackgroundWorkers:
private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
// Check for errors...
}
else if (e.Cancelled)
{
// Mark that this one has finished
}
else
{
// Assuming you have a set of BackgroundWorkers called "workers"
foreach (var bgw in workers)
bgw.CancelAsync();
// other stuff...
}
}
Then, add a bit of code at the end of your DoWork method to report the cancellation...
private void DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
// Do stuff...
// When "RunWorkerCompleted" is called, let it know whether this worker has been cancelled.
e.Cancel = worker.CancellationPending;
}
And that's it. You can also check the worker.CancellationPending periodically to see if you can finish earlier, but don't forget to assign worker.CancellationPending to e.Cancel before your return!
One last thing: if you want the postprocessing to continue when all workers have finished (and only then), you need to have a way to mark when a particular worker is finished (to cancel the others), and then a way to find out when they've all finished (so you can begin postprocessing). It's doable, and not too difficult - off the top of my head, I'd use a Dictionary<BackgroundWorker, bool> to indicate which workers have finished. Still, that's another piece of clutter you can avoid with async/await.
From this answer it seems there is no way to kill a Backgroundworker. However this answer shows a workaround by overriding OnDoWork and keeping a reference to Thread.CurrentThread. I would still try to have those Backgroundworkers check for a notification to cancel, though.

windows forms timer: is lock required

I have a button on my application whose click event:
private void btn_Click(object sender, EventArgs e)
{
btn_DoMyAction();
}
and btn_DoMyAction is
private void btn_DoMyAction()
{
//lock (_lock) //--> Is this necessary
{
...
... //long code block(I mean non automic)
...
}
}
I am calling btn_DoMyAction from both click event and from windows timer tick
private void myTimer_Tick(object sender, EventArgs e)
{
btn_DoMyAction();
}
I have two questions:
1-) Is lock necessary in btnProcessNextBandBarcode_DoMyAction (I am asking first question, because as far as I debug, it seems it queues call, and lock seems to be unnecessary)
2-) I want to skip thread instead of queue on tick or button click
Additional question is:
if the answer no for first question, if btn_DoMyAction is called from Thread(None timer), how should I take action for automicity
It depends on which timer are you using. If you grab timer from toolbox, you're using System.Windows.Forms.Timer. According to the documentation,
This Windows timer is designed for a single-threaded environment where UI threads are used to perform processing.
So you don't have to use lock because btn_Click and myTimer_Tick are executed in the same thread.
Additional question:
If you call btn_DoMyAction from another thread, in gerenal you should use lock because it might be called from UI thread and another thread.
EDIT:
2. Because Timer is executed in UI thread and action executed on click on button is also executed in UI, situation that tick arrive and but previous execucion does not comlpleate cannot occure (because everything is executed in one thread). If you would like timer that start execution after particular time passes from complition of this action, you should use diferent timer - System.Threading.Timer should be ok - you can start timer at the end of execution (when execution caused by timer).

c# calling backgroundWorker from another thread than UI thread

I'm trying to load loadingForm like below code. But it doesn't work, the loadingForm doesn't disappear, the event RunWorkerCompleted doesn't get called.
And also, I need to call loadingForm and backgroundWorker multiple times, so how do I completely dispose the loadingForm and the backgroundWorker after each call?
I think that there're many things wrong in my code but I don't know how to fix it. Could you show me how to solve my problem and point out where I need to fix? Thanks a lot in advance.
public partial class loginForm : Form
{
//....
private loadingForm lf;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
lf.Show();
While (backgroundWorker1.isBusy)
Application.DoEvents();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, DoWorkEventArgs e)
{
lf.Close();
}
private void connect()
{
//....
Thread mainThread = new Thread(ThreadStart(listentoServer));
mainThread.Start();
}
private void listentoServer()
{
//....
lf = new loadingForm();
backgroundWorker1.RunWorkerAsync();
//....
backgroundWorker1.CancelAsync();
//....
}
}
There's a lot of things wrong with your code. If you can, try to take a step back and describe what exactly you want to do.
BackgroundWorker uses the Event-based Asynchronous Pattern (EAP). As such, it requires a thread context in which to live. UI threads satisfy this requirement, but manually-created Thread instances do not (unless you install one or make the instance a secondary UI thread).
Similarly, UI components bind to a particular thread. They require an STA thread that does message pumping (e.g., Application.DoEvents).
It looks to me like you're creating a manual Thread and then creating UI components from that thread (so you know that the thread should be STA and include a message pumping loop, neither of which are in your code). Then that thread starts a BGW which does message pumping.
It's not clear what you're trying to accomplish here - maybe displaying a dialog in a separate thread?
Multiple UI threads in a WinForms app is not an officially supported scenario AFAIK, though some people have gotten it working. I've never seen a need for it, though.
According to what you have shown (which is admittedly incomplete, so this may not be the problem), you are not hooking up your event to the backgroundWorker_DoWork and backgroundWorker_RunWorkerCompleted event handlers. Somewhere (after you instantiate your backgroundWorker), you should have this:
backgroundWorker.DoWork += new EventHandler(backgroundWorker_DoWork);
backgroundWorker.RunWorkerCompleted += new EventHandler(backgroundWorker_RunWorkerCompleted);
As a disclaimer, this was written by hand, so the event names or EventHandler types may be incorrect.
i really don't know how to fix your code definitively, or if your code even works the way you have it, i can only give you the following guidance.
use CancellationPending property of background worker, not the IsBusy property
when working with windows forms and threaded code, always use the Invoke/BeginInvoke methods to make sure you marshal your call back to the thread that the control originated from.

Winforms application hangs when switching to another app

I believe I have a potential threading issue. I have a user control that contains the following code:
private void btnVerify_Click(object sender, EventArgs e)
{
if (!backgroundWorkerVerify.IsBusy)
{
backgroundWorkerVerify.RunWorkerAsync();
}
}
private void backgroundWorkerVerify_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
VerifyAppointments();
}
private void backgroundWorkerVerify_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Information was Verified.", "Verify",
MessageBoxButtons.OK, MessageBoxIcon.Information);
CloseEvent();
}
vanilla code. but the issue I have is that when the application is running and the users tabs to another application when they return to mine the application is hung, they get a blank screen and they have to kill it. This started when I put the threading code. Could I have some rogue threads out there? what is the best way to zero in a threading problem? The issue can't be recreated on my machine...I know I must be missing something on how to dispose of a backgroundworker properly. Any thoughts are appreciated, Thanks,
Jose
Your code snippet doesn't explain it, but deadlocking the UI thread is never that difficult when you use BGW and are interested in its IsBusy property. A deadlock like this is usually easy to diagnose, use Debug + Break All. Then Debug + Windows + Threads and double-click the Main Thread. Then Debug + Windows + Call Stack to see what the UI thread is doing.
The common scenario is that the UI thread is looping on the IsBusy property. The BGW can't complete because its RunWorkerCompleted event can't run until the UI thread goes idle.
Are you accessing the GUI from the VerifyAppointments() method? You should utilize the DoWorkEventArgs in order to pass in the arguments you are verifying and you should not access the GUI from the BackgroundWorker directly.
You can safely access the GUI only in the RunWorkerCompleted or the ProgressChanged events.

Categories