issues with BackGround worker across classes - wpf

this is my first question in this forum, hope it will not be duplicated somewhere because i have searched for the respons for almost 4 weeks without making any progress.
here is my situation,
im developing an application that need to do a lot of background operation, for that reason i creat 2 BKW, the first one used to load data from a DB and put it inside an observable collection , 'no need to report progress or support cancelation for this one' :
private Boolean loadTestSteps()
{
// Create a background worker thread that don't report progress and does not
// support cancelation
BackgroundWorker wk_LoadTestSteps = new BackgroundWorker();
wk_LoadTestSteps.DoWork += new DoWorkEventHandler(wk_LoadTestSteps_DoWork);
wk_LoadTestSteps.RunWorkerAsync();
return true;
}
observable collection class :
public class clsTestStep : DependencyObject
{
public static DependencyProperty TestStepProperty = DependencyProperty.Register(
"TestStep", typeof(String), typeof(clsTestStep));
public string TestStep
{
get { return (string)GetValue(TestStepProperty); }
set { SetValue(TestStepProperty, value); }
} and so on for the rest of items....
now the main backGround that should do the longer operation and in the same time report the progress to the main UI ,declared like so
private void InitializeBackGroundWork()
{
_wk_StartTest = new BackgroundWorker();
// Create a background worker thread that ReportsProgress &
// SupportsCancellation
// Hook up the appropriate events.
_wk_StartTest.DoWork += new DoWorkEventHandler(_wk_StartTest_DoWork);
_wk_StartTest.ProgressChanged += new ProgressChangedEventHandler
(_wk_StartTest_ProgressChanged);
_wk_StartTest.RunWorkerCompleted += new RunWorkerCompletedEventHandler
(_wk_StartTest_RunWorkerCompleted);
_wk_StartTest.WorkerReportsProgress = true;
_wk_StartTest.WorkerSupportsCancellation = true;
_wk_StartTest.RunWorkerAsync();
}
in the do work events, exactly in the foreach loop i encontered an error saying : you cannot access this object because another thread own it :
void _wk_StartTest_DoWork(object sender, DoWorkEventArgs e)
{
//Loop through each test step and perform Test
foreach (clsTestStep item in _testStep)
{
Thread.Sleep(200);
temp[0] = item.TestStep;
temp[1] = item.Delay.ToString();
temp[2] = item.NumberRepetition.ToString();
temp[3] = item.Mode.ToString();
//Report % of Progress, Test step Name,and the paragraph from Class PerformTest
_wk_StartTest.ReportProgress(counter,
temp[0]);
counter += 1;
_performTest.Fdispatcher(temp, out _paragraph);
//_si.PgBarMax = Convert.ToDouble(_testStep.Count);
}
//Report completion on operation completed
_wk_StartTest.ReportProgress(counter);
}
what im missing here please, because my head is gonna explod from searching !!!

It sounds like your ObservableCollection is created and so owned by an other thread so your _wk_StartTest_DoWork method can't access it.
Where your _testStep variable comes from ?
By the way, in a multithread environment when many thread access the same data you should prefer the use of ConcurrentBag class instead of an ObservableCollection. ConcurrentBag is thread safe.

for the ones that may enconter this kind of problem ^^
finnaly i have found a way to acess class even if its not owned by the current thread here a nice article explaining step by step how to do this here

Related

Windows Form UI Update issue with Task in C#

We are working on a windows application which caters to an engineering calculation which are essentially very long running. So we are basically trying to keep the calculation module separate and working in a separate worker thread and pass it an Action delegate in method signature which will be invoked to report the calculation progress in the UI. The delegate handler declared in the UI will be updating the UI. We found that while a huge loop is running in the calculation, the UI is not showing the periodic progress and only displaying the final result. If a Thread Sleep for 1 millisecond is introduced in the calculation loop, the UI is getting updated correctly. This is not expected behavior as we are executing the calculation using a separate Task and updating the UI using BeginInvoke calls.
I have created a simple application to demonstrate our approach and code so that it is easier to understand. It is obvious that we are missing something very simple but cannot quite pin it down. Will appreciate any insights.
Thanks for reading.
private void cmdStart_Click(object sender, EventArgs e)
{
txtResultDIsplay.Text = "";
var maxIterations = long.Parse(txtIterationNo.Text.Trim());
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Task<double> calculationTask = Task.Factory.StartNew<double>(
() => SumRootN(maxIterations, UpdateProgress));
var handleResultTask = calculationTask.ContinueWith((t) => DisplayResult(t),
CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, ui);
}
private void DisplayResult(Task<double> calculationTask)
{
txtResultDIsplay.Text = "Final Calculation Result : " + calculationTask.Result.ToString();
}
private void UpdateProgress(string msg)
{
this.BeginInvoke((MethodInvoker)delegate
{
txtResultDIsplay.Text = msg;
});
}
public double SumRootN(long maxIterations, Action<string> progressUpdateDelegate)
{
int root = 20;
double result = 0;
for (long i = 1; i < maxIterations; i++)
{
Thread.Sleep(1);
result += Math.Exp(Math.Log(i) / root);
progressUpdateDelegate(result.ToString("0.00000"));
}
return result;
}
It is possible you are flooding the UI thread with your progress updates. You need to find a way to prevent lots of updates occurring.
We can solve the problem using tasks!
Task progressTask = null;
private void UpdateProgress(string msg)
{
//only schedule work if the task if not running
if(progressTask == null || progressTask.IsCompleted) //updates will end if there is an exception!
{
//Create a task representing the update
progressTask = Task.Factory.FromAsync<object>(BeginInvoke(new Action(() => txtResultDIsplay.Text = msg)), this.EndInvoke)
.ContinueWith(() => System.Threading.Thread.Sleep(100)); //add a sleep on the end
}
}
Note that locking will not do here as you want to skip the update if there is already an update occurring.

run multiple tasks in parallel using C#.net 2.0

I need to perform 2 tasks in parallel. One will load data in the GUI, till then I want to run a progress bar continuously in front of user. I tried BackgroundWorker but it is giving me some Thread synchronization error. Can somebody suggest me any other best way of doing same.
Code:
backgroundWorker1 initialization:
backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
if (backgroundWorker1.IsBusy != true)
{
backgroundWorker1.RunWorkerAsync();
}
error coming on following line:
XmlDocumentHierarchy _remoteObj = new XmlDocumentHierarchy(comboBox2.Text, "username", "password");
is:
"Cross-thread operation not valid: Control 'comboBox2' accessed from a thread other than the thread it was created on."
You are trying access comboBox2.Text in thread other than GUI thread (background worker thread). If you using only one property in background worker thread, than you can pass `comboBox2.Text' to background worker method:
if (backgroundWorker1.IsBusy != true)
{
backgroundWorker1.RunWorkerAsync(comboBox2.Text);
}
In backgroundWorker1_DoWork procedure you can read property in following way:
void backgroundWorker1_DoWork(Object sender, DoWorkEventArgs e)
{
String comboBoxText = (String)e.Argument;
XmlDocumentHierarchy _remoteObj = new XmlDocumentHierarchy(comboBoxText, "username", "password");
}
If you accessing more than one property from GUI controls you can create simple class to pass all necessary data to your background worker method.
If you need to access GUI thread from BackgroundWorker thread, you can easily invoke your methods in the GUI thread like this:
public Form1()
{
InitializeComponent();
Thread thr = new Thread(new ThreadStart(BackGroundThread));
thr.Start();
}
void BackGroundThread()
{
for (int i = 0; i < 100; i++)
{
// The line below will be run in the GUI thread with no synchronization issues
BeginInvoke((Action)delegate { this.Text = "Processed " + i.ToString() + "%"; });
Thread.Sleep(200);
}
}

Dynamic Threading with Start, Pause and Stop event handling

I have created sample application and implemented threading. basically aim to craete this application is i would like to
If any process(s) are runnig then User Interface should Notify
[DONE]
Handle dynamically created thread with ProgressBar [DONE]
Provide addition functionality to Start, Pause and Stop thread from
available progress list. [NEED YOUR HELP]
Note:- I don't have much knowledge about Threading and Delegates, so please let me know best solution for existing code.
Files and Controls are used:-
Basically three files are used in this demo application
ProgressForm.cs (Window Form)
which conatains Button for creating new progress and Container whic will hold all the created progressbars
ProgressClass.cs
Which contains Dynamic Threading and Delegates to Notify UI without locking or hanging user interface
ProgressControl.cs (User Control)
Which contains
Progressbar (to display process done)
Precent Label (display percentage of completed progress)
Start/Pause button (for play/pause a thread)
Stop button (stop running thread and remove progress from list)
StartTime Label (display process started time)
EndTime label (display time of process completed)
MaxValue Lable (generate random number between 25 to 100)
CODE SNIPPET:-
1. ProgressForm .cs
public partial class ProgressForm : Form
{
Random randomMaxValue = new Random();
public ProgressForm()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
ProgressClass m_clsProcess;
ProgressControl progress = new ProgressControl();
progress.StartedAt = DateTime.Now;
progress.MinValue = 0;
progress.CurrentValue = 0;
progress.MaxValue = randomMaxValue.Next(25, 100);
AddControl(progress);
m_clsProcess = new ProgressClass(progress, this, new ProgressClass.NotifyProgress(DelegateProgress));
m_clsProcess.Start();
}
private void DelegateProgress(int CurrentValue, ProgressControl Progress)
{
ProgressBar p = (ProgressBar)Progress.Controls.Find("pgbPercent", false)[0];
p.Minimum = Progress.MinValue;
p.Value = CurrentValue;
p.Maximum = Progress.MaxValue;
Label percent = (Label)Progress.Controls.Find("lblPercent", false)[0];
percent.Text = string.Format("{0:#00} %", Convert.ToInt16((CurrentValue * 100) / Progress.MaxValue));
Label start = (Label)Progress.Controls.Find("lblStart", false)[0];
start.Text = string.Format("{0:HH:mm:ss}", Progress.StartedAt);
if (CurrentValue == Progress.MaxValue)
{
Label complete = (Label)Progress.Controls.Find("lblComplete", false)[0];
complete.Text = string.Format("{0:HH:mm:ss}", DateTime.Now);
Progress.Status = ProgressControl.ProgressStatus.Completed;
}
Label max = (Label)Progress.Controls.Find("lblMaxValue", false)[0];
max.Text = string.Format("{0:#00}", Progress.MaxValue);
Button btnstartstop = (Button)Progress.Controls.Find("btnStartStop", false)[0];
btnstartstop.Click += new EventHandler(ProgressStartStop);
}
private void AddControl(Control ctl)
{
tableLayoutPnl.RowCount += 1;
tableLayoutPnl.RowStyles.Add(new RowStyle());
ctl.Dock = DockStyle.Fill;
tableLayoutPnl.Controls.Add(ctl, 0, tableLayoutPnl.RowCount - 1);
}
void ProgressStartStop(object sender, EventArgs e)
{
Button btn = sender as Button;
//
//Here i would like to write a code for START / PAUSE thread and update Image acording too.
//
}
}
2. ProgressControl.cs
public partial class ProgressControl : UserControl
{
public enum ProgressStatus
{
Initialize,
Running,
Paused,
Completed
}
public DateTime StartedAt { get; set; }
public DateTime CompletedAt { get; set; }
public int MinValue { get; set; }
public int CurrentValue { get; set; }
public int MaxValue { get; set; }
public ProgressStatus Status { get; set; }
public ProgressControl()
{
InitializeComponent();
this.Status = ProgressStatus.Initialize;
}
}
3. ProgressClass.cs
public class ProgressClass
{
private int ThreadWaitTime = 100;
private ProgressControl m_progress;
private NotifyProgress m_clsNotifyDelegate;
private System.Threading.Thread m_clsThread;
private System.ComponentModel.ISynchronizeInvoke m_clsSynchronizingObject;
public delegate void NotifyProgress(int PercentComplete, ProgressControl Progress);
public ProgressClass(ProgressControl Progress, System.ComponentModel.ISynchronizeInvoke SynchronizingObject, NotifyProgress NotifyDelegate)
{
m_progress = Progress;
m_clsSynchronizingObject = SynchronizingObject;
m_clsNotifyDelegate = NotifyDelegate;
}
public void Start()
{
m_clsThread = new System.Threading.Thread(DoProcess);
m_clsThread.Name = "Background Thread";
m_clsThread.IsBackground = true;
m_progress.Status = ProgressControl.ProgressStatus.Running;
m_clsThread.Start();
}
private void DoProcess()
{
for (int i = m_progress.MinValue; i <= m_progress.MaxValue; i++)
{
NotifyUI(i);
Thread.Sleep(ThreadWaitTime);
}
}
private void NotifyUI(int Value)
{
object[] args = new object[2];
args[0] = Value;
args[1] = m_progress;
m_clsSynchronizingObject.Invoke(m_clsNotifyDelegate, args);
}
}
I am not asking for write whole code instead of provide hint.
I would like to start/pause relevent thread from list, os what should i do for that?
I would like hind in following function:
void ProgressStartStop(object sender, EventArgs e)
{
Button btn = sender as Button;
//Here i would like to write a code for START / PAUSE thread and update Image acording too.
}
UPDATED:
You will want to use a ManualResetEvent or ManualResetEventSlim to create the pause and resume behavior in the thread. The idea is to check the state of the event in the worker thread at safe points. This is done via the WaitOne or Wait methods. If the event is signaled then the calls will return immediately allowing the thread to proceed. If the event is unsignaled then the calls block until the event is signaled via the Set method. So to pause the thread you would call Reset to unsignal the event and to resume the thread you would call Set.
Just remember to place calls to WaitOne or Wait at safe points in the instruction sequence of the worker thread. In other words, do not call these methods inside a lock or something like that. At the beginning or end of a loop is often a good start.
Also, it looks like you use the Invoke method for updating the UI. That is all fine and good, but for simply updating the UI with progress information there is a better option. It is better to publish the progress information to a shared data structure and then have the UI thread pick it up via a timer. For those that monitor my answers I harp about this a lot, I know. But, this strategy has a lot of advantages.
It breaks the tight coupling between the UI and worker threads that Invoke imposes.
It puts the responsibility of updating the UI thread on the UI thread where it should belong anyway.
The UI thread gets to dictate when and how often the update should take place.
There is no risk of the UI message pump being overrun as would be the case with the marshaling techniques initiated by the worker thread.
The worker thread does not have to wait for an acknowledgement that the update was performed before proceeding with its next steps (ie. you get more throughput on both the UI and worker threads).
It avoids the subtle race conditions that can occur when trying to gracefully end the worker thread.
It is more efficient since Invoke is an expensive operation.
Update:
Here is the general idea regarding the changes that could be made to ProgressStartStop.
private Dictionary<int, ThreadInfo> threads = new Dictionary<int, ThreadInfo>();
void ProgressStartStop(object sender, EventArgs e)
{
Button button = sender as Button;
int index = GetThreadIndexFromButton(button);
if (!threads.ContainsKey(index))
{
// The thread has not been started yet so do it now.
var thread = new Thread(RunThread);
thread.Start();
var mres = new ManualResetEventSlim(true);
var info = new ThreadInfo { Thread = thread, ProceedSignal = mres };
threads.Add(index, info);
// Change the button image here.
}
else
{
ThreadInfo info = threads[index];
if (info.ProceedSignal.Wait(0))
{
// The event is signaled which means the thread is running. Pause it.
info.ProceedSignal.Reset();
// Change the button image here.
}
else
{
// The event is unsignaled which means the thread is paused. Resume it.
info.ProceedSignal.Set();
// Change the button image here.
}
}
}
private class ThreadInfo
{
Thread Thread { get; set; }
ManualResetEventSlim ProceedSignal { get; set; }
}
It is generally considered bad practice to Suspend threads (though it is possible). The right way to pause and terminate threads is through the cooperation with the job that the thread is doing. The job should check a variable in a loop, and pause or exit accordingly. The controlling program can set that variable, and if you need feedback the background thread can call a notification method before exiting or sleeping.

WPF System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it

In my Windows I have a TextBox which I like to update (text property) from another thread. When doing so, I get the InvalidOperationException (see title). I have found different links in google explaining this, but I still can't seem to make it work.
What I've tried is this:
Window1 code:
private static Window1 _myWindow;
private MessageQueueTemplate _messageQueueTemplate;
private const string LocalTemplateName = "LocalExamSessionAccessCodeMessageQueueTemplate";
private const string RemoteTemplateName = "RemoteExamSessionAccessCodeMessageQueueTemplate";
...
public Window1()
{
InitializeComponent();
_myWindow = this;
}
public static Window1 MyWindow
{
get
{
return _myWindow;
}
}
public void LogText(string text)
{
informationTextBox.Text += text + Environment.NewLine;
}
...
In another class (actually a spring.NET Listener adapter, listening to a certain queue, started in another thread).
var thread = new Thread(
new ThreadStart(
delegate()
{
Window1.MyWindow.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
Window1.MyWindow.LogText(text);
}
));
}
));
It doesn't throw an error, but the text in the LogText method in Window1 isn't triggered, so the text isn't updated.
So basically, I want to update this TextBox component from another class running in another thread.
Window1.MyWindow.informationTextBox.Dispatcher.Invoke(
DispatcherPriority.Normal,
new Action(() => Window1.MyWindow.informationTextBox.Text += value));
Well, using Dispatcher.Invoke or BeginInvoke is definitely the way to go, but you haven't really shown much code other than creating a thread - for example, you haven't started the thread in your second code block.
If you put the Dispatcher.Invoke code in the place where previously you were getting an InvalidOperationException, it should be fine.
For WPF, I find this construct:
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += ( s, e ) =>
{
};
bw.RunWorkerCompleted += ( s, e ) =>
{
};
bw.RunWorkerAsync();
to be the most useful. The RunWorkerCompleted block will typically update an ObservableCollection or fire off a RaisePropertyChangedEvent.

2 Issues with BackgroundWorker component

Firstly, I know I should be using proper Threading techniques (Threadpool, BeginInvoke, etc.) to accomplish this, but thats a bit over my head currently and will call for some time to read over material and understand it (if you have any URL references for my scenario, please feel free to post it).
In the interim I am using the backgroundWorker to pull a very large resultset and populate a DatagridView with it. I successfully create a SortableBindingList<TEntities> in my DoWork event and pass that out in the result. And in the RunWorkerCompleted event, I cast and bind that SortableBindingList<TEntities> to my Grid. My 2 main areas of concern are as follows:
1) Access to private variables.
I want to pass one of two parameters List<long> into my DoWork event, but run a different query depending on which list was passed to it. I can get around this by declaring a class-level private boolean variable that acts a flag of sorts. This seems silly to ask, but in my DoWork, am I allowed to access that private variable and route the query accordingly? (I've tested this and it does work, without any errors popping up)
private bool SearchEngaged = false;
private void bgw_DoWork(object sender, DoWorkEventArgs e) {
BackgroundWorker worker = sender as BackgroundWorker;
e.Result = GetTasks((List<long>)e.Argument, worker, e);
}
SortableBindingList<Task> GetTasks(List<long> argsList, BackgroundWorker worker, DoWorkEventArgs e) {
SortableBindingList<Task> sbl = null;
if (worker.CancellationPending) {
e.Cancel = true;
}
else {
if (SearchEngaged) {
sbl = DU.GetTasksByKeys(argsList);
}
else {
sbl = DU.GetTasksByDivision(argsList);
}
}
return sbl;
}
2) UI Thread freezes on beginning of RunWorkerCompleted.
Ok, I know that my UI is responsive during the DoWork event, 'cos it takes +/- 2seconds to run and return my SortableBindingList<Task> if I don't bind the List to the Grid, but merely populate it. However my UI freezes when I bind that to the Grid, which I am doing in the RunWorkerCompleted event. Keep in mind that my Grid has 4 image columns which I handle in CellFormatting. This process takes an additional 8 seconds to accomplish, during which, my UI is completely non-interactive. Im aware of the cross-thread implications of doing so, but is there any way I can accomplish the Grid population and formatting either in the background or without causing my UI to freeze? RunWorkeCompleted looks like so:
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Cancelled) {
lblStatus.Text = "Operation was cancelled";
}
else if (e.Error != null) {
lblStatus.Text = string.Format("Error: {0}", e.Error.Message);
}
else {
SortableBindingList<Task> sblResult = (SortableBindingList<Task>)e.Result;
dgv.DataSource = sblResult;
dgv.Enabled = true;
TimeSpan Duration = DateTime.Now.TimeOfDay - DurationStart;
lblStatus.Text = string.Format("Displaying {0} {1}", sblResult.Count, "Tasks");
lblDuration.Visible = true;
lblDuration.Text = string.Format("(data retrieved in {0} seconds)", Math.Round(Duration.TotalSeconds, 2));
cmdAsyncCancel.Visible = false;
tmrProgressUpdate.Stop();
tmrProgressUpdate.Enabled = false;
pbStatus.Visible = false;
}
}
Sorry for the lengthy query, but I will truly appreciate your responses! thank you!
Your code appears to be doing exactly the right thing.
As for the 8 seconds that it takes for the UI thread to update the screen, there's not much you can do about that. See my answer to this question.
To optimise the UI part, you could try calling SuspendLayout and ResumeLayout on the grid or its containing panel.
You could also look at trying to reduce the amount of processing that is done during the data binding. For example:
Calculations done in the grid could be moved into the data model (thereby doing them in the worker thread).
If the grid auto-calculates its columns based on the data model, then try hard-coding them instead.
EDIT: Page the data in the Business Layer and make the grid only show a small number of rows at a time.
I think the easiest solution for your problem is setting the datasource of your grid in DoWork instead of RunWorkerCompleted using Dispatcher.BeginInvoke which you have mentioned yourself. Something like this:
private bool SearchEngaged = false;
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
SortableBindingList<Task> sblResult = GetTasks((List<long>)e.Argument, worker, e);
BeginInvoke((Action<object>)(o => dataGridView1.DataSource = o), sblResult);
}
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled) {
lblStatus.Text = "Operation was cancelled";
}
else if (e.Error != null) {
lblStatus.Text = string.Format("Error: {0}", e.Error.Message);
}
else
{
dgv.Enabled = true;
TimeSpan Duration = DateTime.Now.TimeOfDay - DurationStart;
lblStatus.Text = string.Format("Displaying {0} {1}", sblResult.Count, "Tasks");
lblDuration.Visible = true;
lblDuration.Text = string.Format("(data retrieved in {0} seconds)", Math.Round(Duration.TotalSeconds, 2));
cmdAsyncCancel.Visible = false;
tmrProgressUpdate.Stop();
tmrProgressUpdate.Enabled = false;
pbStatus.Visible = false;
}
}
As far as the private variable issue is concerned, I don't think it will be of any problem in your case. In case you are changing it using some UI event, just mark the private field as volatile. The documentation of the volatile keyword can be found here:
http://msdn.microsoft.com/en-us/library/x13ttww7.aspx

Resources