What is alternative of Thread.Join() to overcome UI freezing issue - c#

I have two thread which start running When user select play button.
But when use select Pause or Resume button my UI hangs because of Thread.Join().
Below is code, I am looking for some alternative to overcome this.
I already tried with Invoke but it's not working even with this approach my UI freeze the moment I call Thread methods.
ThreadStart m_executeThreadStart;
Thread m_executeThread;
//user Selected Start Button
private void Start()
{
m_executeThreadStart = new ThreadStart(method1);
m_executeThread = new Thread(m_executeThreadStart);
m_executeThread.Name = "ExecuteTestSession";
m_executeThread.IsBackground = true;
m_executeThread.Start();
// Start the asynchronous operation.
// InitializeBackgroundWorker();
// backgroundWorker1.RunWorkerAsync();
//Creating result sync thread
ThreadStart m_resultSyncThreadStart = new ThreadStart(method2);
Thread m_resultSyncThread = new Thread(m_resultSyncThreadStart);
m_resultSyncThread.Name = "SyncResultDatabase";
m_resultSyncThread.Start();
}
private void method1()
{
//do some work
//read data from OPC sever (device)
}
private void method2()
{
//do some work
//updated database accordingly method 1 data
}
//user Press Pause button
public void Suspend()
{
//do work
m_executeThread.Join();
//do work
}
//user Press Resume button
public void Resume()
{
//do work
m_executeThread.Join();
//do work
}

You can add an event handler to your background worker, then you don't need Thread.Join(). Your event handler can then perform the necessary actions when the long running process has completed:
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// code to run after long running process has completed
}
The async / await pattern was designed to stop the UI from freezing (when implemented correctly) you could use this as an alternative approach - https://learn.microsoft.com/en-us/dotnet/csharp/async
Also see: https://learn.microsoft.com/en-us/windows/uwp/debug-test-perf/keep-the-ui-thread-responsive

i founded solution , below is link for answer.
How to pause/suspend a thread then continue it?
ManualResetEvent mrse = new ManualResetEvent(true);
ThreadStart m_executeThreadStart;
Thread m_executeThread;
//user Selected Start Button
private void Start()
{
m_executeThreadStart = new ThreadStart(method1);
m_executeThread = new Thread(m_executeThreadStart);
m_executeThread.Name = "ExecuteTestSession";
m_executeThread.IsBackground = true;
m_executeThread.Start();
// Start the asynchronous operation.
// InitializeBackgroundWorker();
// backgroundWorker1.RunWorkerAsync();
//Creating result sync thread
ThreadStart m_resultSyncThreadStart = new ThreadStart(method2);
Thread m_resultSyncThread = new Thread(m_resultSyncThreadStart);
m_resultSyncThread.Name = "SyncResultDatabase";
m_resultSyncThread.Start();
}
private void method1()
{
//do some work
//read data from OPC sever (device)
mrse.WaitOne();
}
private void method2()
{
//do some work
//updated database accordingly method 1 data
mrse.WaitOne();
}
//user Press Pause button
public void Suspend()
{
//do work
mrse.Reset();
//do work
}
//user Press Resume button
public void Resume()
{
//do work
mrse.Set();
//do work
}
Appreciated your help.

Related

c# which is the best way for doing a larger task without interrupting whole program

My question is i want to execute some operations like fetching the data ( format is string )from some URL . and i want run this process to be background. i have to call this operations whenever user needs this. like if a user clicks a button specified for this operation, it should execute the function and provide result to that user. Problem is when ever executing this no other program should not get interrupted. I want to run this Asynchronous way . i want to return the result which is downloaded from the URL
Here is my solution using thread
namespace xyz
{
public class newWinForm : Form
{
SomeClass someClass = new SomeClass();
public newWinForm()
{
Thread backgroundThread = new Thread(DoWork);
backgroundThread.IsBackground = true;
backgroundThread.Start();
}
void DoWork()
{
try
{
Console.WriteLine("Doing some work...");
using(WebClient cl = new WebClient())
{
string result = cl.DownloadString("http://www.......com");
}
Thread.Sleep(1000);
}
finally
{
Console.WriteLine("This should be always executed");
}
}
private void getDataFrmUrlButton_Click(object sender, EventArgs e)
{
Thread backgroundThread = new Thread(DoWork);
backgroundThread.IsBackground = true;
backgroundThread.Start();
}
}
You can use backgroundworker class in order to achieve your task
private BackgroundWorker bg1 = new BackgroundWorker();
bg1.DoWork += bg1_DoWork;
private void bg1_DoWork(object sender, DoWorkEventArgs e)
{
//the function you want to execute
}
In this case your operation is I/O bound, so an asynchronous approach is best. To do this you can use the async keyword on your events.
private async void getDataFrmUrlButton_Click(object sender, EventArgs args)
{
using(var client = new WebClient())
{
string result = await client.DownloadStringTaskAsync(uri);
// Do stuff with data
}
}
This post gives some good resources for more information on async/await.
If you want a more enterprise based solution you can have a look at Hangfire (https://www.hangfire.io/).
While normally targeted at ASP.NET solutions you can also run it as part of a windows service and use that in conjunction with your WinForm based application(s). It will allow you to easily hand off long running tasks and track them even if you don't want to to use TPL to do it yourself.

Why isn't my multithreaded app doing what it should do?

I'm using the ThreadPool to manage my threads. Separately from the UI thread I have a thread that does data retrieval and general work operations and I have a 3rd thread that updates the UI to reflect the status of requested operations.
See code below:
// ui thread
private void btnLoadClients_Click(object sender, EventArgs e)
{
// start thread 1
ThreadPool.QueueUserWorkItem(new Form1().LoadClientList);
}
// thread 1
private void LoadClientList(object state)
{
ThreadBusy = true;
ThreadAction = "Loading Clients...";
// start thread 2
ThreadPool.QueueUserWorkItem(new Form1().ShowProgress);
// get data
ClientController c = new ClientController();
List<Client> clients = c.GetClient();
foreach (Client item in clients)
{
cmbClientList.Items.Add(item.Name);
}
cmbClientList.Items.Insert(0, "Please select a client");
ThreadBusy = false;
}
// thread 2
private void ShowProgress(object state)
{
while (ThreadBusy)
{
foreach (string action in lstAction.Items)
{
// write the action that's being taken to the listbox
if (String.Compare(action, ThreadAction) != 0)
lstAction.Items.Add(ThreadAction);
}
}
}
Problem is that although ShowProgress is being hit when I set a breakpoint on it, execution isn't entering it really. The while (ThreadBusy) line isn't getting hit ever.
Have I got anything wrong here?
ThreadPool.QueueUserWorkItem(new Form1().LoadClientList);
ThreadPool.QueueUserWorkItem(new Form1().ShowProgress);
You're creating new Form1 instances every time you start a background thread, every action you take in these methods will happen to these new, "unbounded" instances, not on the one interacting with the user.
If you want to perform background work in WinForms you can leverage the BackgroundWorker class.
A really simple example:
public static class Program
{
public static void Main()
{
var backgroundWorker = new BackgroundWorker();
backgroundWorker.WorkerReportsProgress = true
backgroundWorker.Disposed += BackgroundWorker_Disposed;
backgroundWorker.DoWork += BackgroundWorker_DoWork;
backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
backgroundWorker.RunWorkerAsync();
}
private static void BackgroundWorker_Disposed(object sender, EventArgs e)
{
// Cleanup after yourself.
}
private static void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Do your things in background.
}
private static void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Notify progress.
}
private static void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// The background task is complete ("successfully" is NOT implied).
}
}
ThreadBusy property that you set to true belongs to a different Form1 object. because the thread that runs ShowProgress executes on a new instance of Form1 and its ThreadBusy property is false always. Thats why it is not entering into the while loop.
Can you try this
ThreadPool.QueueUserWorkItem(this.ShowProgress);
instead of
ThreadPool.QueueUserWorkItem(new Form1().ShowProgress);

C# Backgroundworker: What way to periodically update a PictureBox?

I'm using a BackgroundWorker to periodically check a hardware switch. Due to it is connected via a slow RS485 network, I have to delay the next status update.
On switch Status change I want to update an OK/nOK Picture Box. This is realized as a green OK pictureBox over a nOK pictureBox. No real work is done here.
For expandability I decided to use the Backgroundworker. Finally I want to have a hidden worker, which
provides globally the Status of three switches and
updates on StatusChange the PictureBoxes.
Problem description
Once the BackgroundWorker is started, it works as expected. However the GUI freezes.
What did I try?
The MSDN BackgroundWorker Class Note 1
says, that GUI should be updated via ProgressChanged. I tried to raise this Event by Worker_Switch.ReportProgress(fakeProgress++) and failed. The PictureBox wasn't updated anymore.
Snippet from designer
this.Worker_Switch = new System.ComponentModel.BackgroundWorker();
//
// Worker_Switch
//
this.Worker_Switch.WorkerSupportsCancellation = true;
this.Worker_Switch.DoWork += new System.ComponentModel.DoWorkEventHandler(this.Worker_Switch_DoWork);
Snippet from Main Form
delegate void SetEventCallback(object sender, DoWorkEventArgs e); // Threadsafe calls for DoWork
private void btnBackgroundworker_Click(object sender, EventArgs e)
{
if (!Worker_Switch.IsBusy)
{
Worker_Switch.RunWorkerAsync();
}
}
private void Worker_Switch_DoWork(object sender, DoWorkEventArgs e)
{
// Worker Thread has no permission to change PictureBox "pictureBoxSwitchrightOK"
// Therefore this method calls itsself in the MainThread, if necessary.
while (!Worker_Switch.CancellationPending)
{
if (this.pictureBoxSwitchrightOK.InvokeRequired) // Worker Thread
{
System.Threading.Thread.Sleep(400);
SetEventCallback myCall = new SetEventCallback(Worker_Switch_DoWork);
this.Invoke(myCall, new object[] { sender, e });
}
else // Main Thread
{
// Turns OK Picture Box invisible, if nOk State (Switch pushed)
pictureBoxSwitchrightOK.Visible = SwitchOK("right"); // true: OK (green)
this.Refresh();
}
}
private bool SwitchOK(string rightOrLeft) // select one of the switches
{ (...)} // gets hardware switch status
Edit: Special Thanks to laszlokiss88 (3 possibilities) and JMK (for simplicity with System.Windows.Forms Timer from toolbox)
This alternative from Toolbox also worked:
this.timer_Switch.Enabled = true;
this.timer_Switch.Interval = 400;
this.timer_Switch.Tick += new System.EventHandler(this.timer_Switch_Tick);
private void timer_Switch_Tick(object sender, EventArgs e)
{
motorSwitchControl.Init(); // globally available Switch status
SwitchRight = SwitchOK("right");
SwitchRightOK.Visible = SwitchRight;
SwitchLeft = SwitchOK("left"); // globally available Switch status
SwitchLeftOK.Visible = SwitchLeft;
SwitchAllOK = SwitchRight & SwitchLeft;
this.Refresh();
}
a) Is it correct, that the Sleep() actually happens in the Worker Thread?
- no Main Thread
b) What is going wrong, if I manipulate user interface objects in DoWork? (Contrary to MSDN Note)
- works in Main Thread?
c) What is the correct way to periodically update a PictureBox? DoWork, ProgressChanged, RunWorkerCompleted...?
- Three possibilities from laszlokiss88 answer.
You can update the UI from the DoWork event via the Dispatcher, or Control.Begininvoke(winforms), or you can do it via the ProgressChanged event of the BackgroundWorker:
public MainWindow()
{
InitializeComponent();
var bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerAsync();
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// You are in the main thread
// Update the UI here
string data = (string)e.UserState;
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
// You are in a worker thread
(sender as BackgroundWorker).ReportProgress(0, "right");
}
For a start you should almost never have a need to put an active background thead to sleep. I am also not sure why you are constructing/defining the delegate this way, try some thing like
public delegate void UpdatePictureBox();
myDelegate = new UpdatePictureBox(UpdatePictureboxMethod);
then you have a method UpdatePictureBoxMethod
private void UpdatePictureBoxMethod()
{
this.pictureBox1.Image = Properties.Resources.SomeImage;
}
or something simalar, where you pass in the image to update to.
Alternatively you could use the (bgWorker as BackgroundWorker).ReportProgress(progress, object); method. So from the background thread you call
(bgWorker as BackgroundWorker).ReportProgress(progressBarValue, infoBall);
where here class IfoBall will hold all your important information
class InfoBall
{
public int nProgressBar { get; set; }
public int nMaxProgressBar { get; set; }
public Image image { get; set; }
}
then you can pass this object back to the UI thread and do your updates
void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// On UI thread.
InfoBall someBall = (InfoBall)e.UserState;
this.pictureBox1.Image = someBall.image;
// etc...
}
I hope this helps.

c# BeginInvoke Problem

I have a program that makes some hefty calls to the database and then updates the UI. This is causing problems because for most of the time it means that the UI in not responsive. I therefore decided that I wanted to put the function calls that access the database and update the UI in a separate thread, so now I have something like this:
private delegate void CallAsyncDelegate();
private void CallGetDBValues()
{
// Call GetDatabaseValues in new thread
CallAsyncDelegate callGetDatabaseValues = new
CallAsyncDelegate(GetDatabaseValues);
BeginInvoke(callGetDatabaseValues);
}
private void GetDatabaseValues()
{
// Get lots of data here
// Update UI here
}
...
However, it seems to make no difference whatsoever to the UI. I read somewhere that if the code to be run in a separate thread needed to update the UI then this was how the call should be made - is this correct? Am I doing something wrong?
You may be better served using the BackgroundWorker that is built-in to the .NET framework.
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.WorkerReportsProgress = true;
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// update UI with status
label1.Text = (string)e.UserState
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Check for cancel
if(e.Cancelled)
{
//Handle the cancellation.
{
//Check for error
if(e.Error)
{
//Handle the error.
}
// Update UI that data retrieval is complete
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
// Get data
//foreach to process data
//Report progress
bw.ReportProgress(n, message);
}
Here's a link to the MSDN article on how to use the BackgroundWorker for additional details. Thanks to Henk Holterman for the suggestion to include this:
http://msdn.microsoft.com/en-us/library/cc221403%28VS.95%29.aspx
In the "// Update UI here", make sure to use Control.Invoke to actually do the work -- it's imperative that the UI only be "touched" by the UI-thread, and this only happens when you use Control.Invoke.
BeginInvoke and Invoke means to run the code on the UI thread. In this case if you are calling CallGetDBValues() from the UI thread you are not going to gain anything.
Usually you will create a BackgroundWorker or background thread that will do the heavy lifting and it will Invoke back to the UI thread the values that need to be updated.
A BackgroundWorker will probably be the better solution (see Robaticus's answer), but here is a background thread version.
private delegate void CallAsyncDelegate();
private void button_Click( object sender, EventArgs e )
{
Thread thread = new Thread( GetDBValues );
thread.IsBackground = true;
thread.Start();
}
private void GetDBValues()
{
foreach( ... )
{
Invoke( new CallAsyncDelegate( UpdateUI ) );
}
}
private void UpdateUI()
{
/* Update the user interface */
}
I'm not sure of the syntax.. but the sytax I'm more familiar with is something like:
public delegate object myDelegate(object myParam);
Public class MyClass
{
public static void Main()
{
myDelegate d = new myDelegate(myMethod);
d.BeginInvoke ( new object() );
}
static void myMethod(object myParam)
{
// do some work!!
return new object);
}
}

progressBar separate thread

I have question about progressbar show value.
I have this main thread
private void button1_Click(object sender, EventArgs e)
{
progress prog = new progress();
progress.progressEvent += new progress.progressEventHandler(progressEvent);
for(int i=0;i<100;i++)
{
Thread.Sleep(100);
prog.incA();
}
}
void progressEvent(object sender)
{
if (progressBar1.InvokeRequired)
{
//Tady mi to caka az kym nedobehne cyklus for a pak zacne tohleto fungovat
progressBar1.Invoke(new ChangeProgressBarValue(ProgressStep));
}
else
{
ProgressStep();
}
}
public void ProgressStep()
{
progressBar1.PerformStep();
}
public class progress
{
private ThreadStart ts;
private Thread th;
private bool status = true;
public delegate void progressEventHandler(object sender);
public static event progressEventHandler progressEvent;
private int b,a = 0;
public progress()
{
ts=new ThreadStart(go);
th = new Thread(ts);
th.IsBackground = true;
th.Start();
}
public void incA()
{
a++;
if(a==100)
status = false;
}
private void go()
{
while (status)
{
if (a != b)
{
b = a;
if (progressEvent != null)
progressEvent(this);
}
}
th.Abort();
}
}
and my problem is IF start main thread and call IncA this method call event and in event is progressbar invoke
and this invoke waiting to end main thread FOR
why waiting?
thx
Your loop in the main thread is preventing "paint" events from happening. Since you are calling your progress bar's function from withing that thread, you will never see the updates.
You need to move the code to do the incrementing to another thread entirely.
Here is a sample of what you want to do using a Button, a BackgroundWorker, and a ProgressBar:
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
backgroundWorker1.ReportProgress(i);
Thread.Sleep(100);
}
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}
Hope this helps!
The progress bar control is a UI object, and is created on the UI thread. When you call Invoke or BeginInvoke to update it, you are asking the UI thread to do the updating.
However, the UI thread is busy - in your button CLick event handler, you have a loop which Sleep()s the thread and calls prog.IncA in a loop. So it never exits back to the main UI loop (which is what dispatches windows messages and updates the UI). Your progress bar is being updated internally, but it never gets a chance to redraw because the UI thread is "busy".
The "processing" code (that is looping and calling prog.IncA()) should not be running on the UI thread at all - you need to start it off in a separate thread and then exit your Click handler so that the UI can continue to update.
Note that this has a side effect - if your UI thread is running, then the user will be able to continue interacting with your program, and so they can click again on the button and kick off another background thread - so you have to be very careful to make sure that the user can't do anything "dangerous" in the UI while you are busy processing.
I suggest you look at some introduction-to-threading tutorials to get an idea of how to use BackgroundWorker or another mechanism for running code in a separate thread. Once you understand that, you can add a progress bar. (And note that although a progress bar sounds like the simplest thing to do, it is actually rather a difficult thing to do due to the need for the UI thread to continue running but not let the user do anything dangerous during your processing)

Categories

Resources