On what thread does this method runs? C# - c#

I have a method that updates records from the database, and I wonder if this method really runs in my BackGroundWorker thread considering the following:
public partial class Form1 : Form
{
BackgroundWorker bg = new BackgroundWorker();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerAsync();
}
void bg_DoWork(object sender, DoWorkEventArgs e)
{
UpdateDatabaseRecords(); // <-- Does this method runs in my BackGroundWorker?
}
private void UpdateDatabaseRecords()
{
SqlConnection conn = new SqlConnection();
// etc...
}
}
Is there a difference if I coded the update stuffs directly inside the bg_DoWork method?
Something like:
void bg_DoWork(object sender, DoWorkEventArgs e)
{
SqlConnection conn = new SqlConnection();
// etc...
// do the update codes here instead of doing
// it by calling another method.
}

Yes it is executing on a separate thread. No there wouldn't be a difference thread wise if you put it directly in that method.

Functions run in the thread that calls them, due to how function calls are implemented. So, since your background worker is calling the bg_DoWork function, it will be running in the worker's thread.
Because the code snippet appears small, there probably won't be a significant difference in calling another function. If you're just doing that little bit of work, then you can have it all in one function. If you start to increase the complexity of what the worker does, then you may want to start splitting it into many functions.

Yes it runs in a separate thread (background). The only difference is that you don't have access to the DoWorkEventArgs parameter, but you can pass it to your method.

No, there is no difference. Invoking a method creates a new stack-frame for the method call, pushes it onto the call-stack for the current thread, and then transfers control to it. It's also possible that the method may be inlined by the JIT compiler, so you may not see any difference in the disassembly between your 'manually inlined' version and your current version.
Btw, here's the code for BackgroundWorker.RunAsync from reflector:
public void RunWorkerAsync()
{
this.RunWorkerAsync(null);
}
public void RunWorkerAsync(object argument)
{
if (this.isRunning)
{
throw new InvalidOperationException(SR.GetString("BackgroundWorker_WorkerAlreadyRunning"));
}
this.isRunning = true;
this.cancellationPending = false;
this.asyncOperation = AsyncOperationManager.CreateOperation(null);
// the important bit
this.threadStart.BeginInvoke(argument, null, null);
}
As you can see, your code will run in the context of a WorkerThreadStartDelegate.BeginInvoke. This should mean that one of the thread-pool threads will pick it up, which you can verify by testing the value of Thread.CurrentThread.IsThreadPoolThread inside the bg_DoWork method.

I don't think so!
wrapping it in a method don't make it work in different thread, i think all of your code inside bg_DoWork will work on background worker (including all code on UpdateDatabaseRecords method).
there is a ThreadSynchronizationContext class where you can post your method to work on different thread context.
you can test your code on visual studio by put a break point inside bg_DoWork method and UpdateDatabaseRecords method. check it out from "Thread Window" from menu "Debug -> Windows-> Thread" investigate it weather it is work on main thread or worker thread.

Related

Declaring Thread in a Constructor in C#

I´m currently figuring out threads and how to work with them.
At the same time Im working on my understanding on Events/Global Events (just for context).
I defined a thread inside a object with the function the thread will use on thread.Start().
internal class Name
{
private Thread testthread;
private EventWaitHandle globalEvent;
private Eventstest evente = new Eventstest(); //Just to add some methods
public Name(Thread testthread, EventWaitHandle globalEvent)
{
this.testthread = testthread;
this.globalEvent = globalEvent;
}
public void Execute()
{
bool terminate = false;
bool eventset = false;
bool rdy = false;
while (!terminate)
{
if (evente.CheckSysEvent(globalEvent))
{
eventset = true; //This is just to check with debugger if the event was raised elsewhere
}
Thread.Sleep(100);
}
}
}
So now, like in this example in a Windows Forms App, Im trying to set an instance of this class while setting the instance of the thread at the same time (with the work method the should run later on).
Im struggling with this part here.
private void btn_runThread_Click(object sender, EventArgs e)
{
threadClass = new Name(new Thread(ProblemHere), globalEvent);
threadClass.Execute();
}
This is a button which starts the thread with the work its supposed to do.
The variable threadClass is just the initialization in the forms1.cs:
Name threadClass;
I know that it wants a delegate to pass the method which the thread should use on start.
I tried pretty much anything I found and cant make it work.
I cant just pass the method, that doesnt work.
And the stuff I found in the c# documentation is pretty much just passing the method, as far as I understood it.
Which is propably wrong.
And I just noticed, how am I able to actually call on that property/thread.start if its only created on runtime?
Not a full solution, but a bump to get you going:
What I would suggest is a little refactor like this
internal class Name
{
private Thread testthread;
private EventWaitHandle globalEvent;
private Eventstest evente = new Eventstest(); //Just to add some methods
public Name(EventWaitHandle globalEvent)
{
this.testthread = new Thread(Execute); // Creates a Thread, that is directed to execute `Execute`
this.globalEvent = globalEvent;
this.testthread.Start(); // Tells the framework to schedule the thread for execution.
}
private void Execute()
{
bool terminate = false;
bool eventset = false;
bool rdy = false;
while (!terminate)
{
if (evente.CheckSysEvent(globalEvent))
{
eventset = true; //This is just to check with debugger if the event was raised elsewhere
}
Thread.Sleep(100);
}
}
}
And in the Button handler just do
private void btn_runThread_Click(object sender, EventArgs e)
{
threadClass = new Name(globalEvent);
}
Mind that there are still a good portion of mistakes and ooopsies, but at least, this will keep your GUI thread running and you may gain an understanding to go on from here.
A totally different approach (if you are willing to consider it) would be to use a System.Windows.Forms.Timer instead. With that you can have a method called every X time, which would check the state of the globalevent as you are trying to get the thread to doing. The timer, however, makes this a little more convenient.
The typical way would be to create the thread in the constructor, as described in the answer by Fildor.
But I want to point out that using the Thread object directly is rarely the correct way to do things since there are other tools more suited for whatever you are tryibng to do:
If you want to do something compute heavy on a background thread once, and update the UI after it has been done. Use Task.Run and async/await
If you want to do something every X seconds. Use a timer. There are both timers that run on the main thread or a background thread, see differences between timers.
If you want to run an compute heavy operation in parallel, use Parallel.For, possibly in combination with Task.Run.
If you want to call IO intensive methods without freezing the UI, use async/await in combination with the appropriate Async methods.
If you want to create a producer/consumer or other processing pipeline there is the DataFlow library

Background worker in windows form application

I have the following constellation:
MainForm.cs -> Including all my Form Elements
Program.cs -> includes the main part, which is a xmlreader/writer to alter xml attributes in xml files that can be as large as 4gb
So this little app works but of course the UI gets unresponsive and freezes which I want to avoid, I also hope to reduce the duration of this process on the way
I start the call of my xmlread/write method from a BtnClick event:
void BtnApplyChangesClick(object sender, EventArgs e)
{
Program p = Program.Instance;
pbApplyChanges.Minimum = 0;
pbApplyChanges.Step = 1;
Cursor.Current = Cursors.WaitCursor;
foreach(DataGridViewRow cr in dataGridView2.Rows)
{
pbApplyChanges.Maximum = dataGridView2.Rows.Count;
p.changeElements(cr.Cells["Filename"].Value.ToString(), txtTenant.Text, txtDate.Text, txtEvtId2.Text);
pbApplyChanges.PerformStep();
}
Cursor.Current = Cursors.Arrow;
MessageBox.Show("Job done");
}
In the call I use my singleton instance of Program.cs and my main Method there (changeElements) uses 4 String params, that are all taken from information in the Form! (I suppose this is kinda bad practice but it worked so far...)
When I tried to replace this method call with a backgroundWorker (itself made the method call then) I failed as the method call wasn't even made... I found out that UI elements can't be accessed from the BW thread, so I suppose this is also the reason for my method call not working?!
So how can I get this constellation to work? Do I have to pass all 4 string Params AND the class instance (of Program.cs) to the background worker? Is BW even the best tool for the job?
In general the BackgroundWorker shouldn't access any UI-Elements. It's an old advice in Winforms that accessing UI-Elements should just happen from the UI-Thread.
You can use the Background-Worker like this:
private void Main(string[] args)
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += Bw_DoWork;
bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
//Parameter you need to work in Background-Thread for example your strings
string[] param = new[] {"Text1", "Text2", "Text3", "Text4"};
//Start work
bw.RunWorkerAsync(param);
}
//Do your Background-Work
private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
string[] param = e.Argument as string[];
//Process your long running task
e.Result = null; //Set your Result of the long running task
}
//Taking your results
private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Apply your Results to your GUI-Elements
myTextBox1.Text = e.Result.ToString();
}
Background-Worker is some old school stuff by the way, so if you like to learn something new take a look here and inform yourself about the TPL. This gives you a better handling of asynchronous.
In fact I think it's not really good to store 4gb data in a XML-File. Do you think about a Database? Or split the XML-File in many XML-Files? So you would be able to read data in chunks.
I hope this helps you.
I don't use background worker for this. I use normal threads instead. Try this code:
public void ButtonDoWork_Click(eventArgs......) {
DoWorkThread = new Thread(new ThreadStart(DoWork)); // Setup thread
DoWorkThread.isBackground = true; // Its background so, we need to set background flag
DoWorkThread.Start(); // Start the thread
}
private Thread DoWorkThread: // our Thread object
private void DoWork() { // This void contains action that will be performed by thread
//TODO: Background processing. To update UI from another thread use Control.Invoke(...)
}
Please note, I don't tested this code - I write it from my memory and it's late so it can not work.
You can also read about Threads at MSDN :)

How to use progressbar, backgroundworker, windows form together in C#?

I am stuck on an issue where I am using Backgroundworker to show the progress of my work in a progress bar. Code used for backgroundworker:-
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(200);
for (int i = 0; i <= 100; i++)
{
Delegate del= new DELEGATE(simulateHeavyWork);
this.Invoke(del);
backgroundWorker1.ReportProgress(i);
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
backgroundWorker1.ReportProgress(0);
return;
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
percentLabel.Text = e.ProgressPercentage.ToString() + "%";
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("Cancelled");
}
else
{
MessageBox.Show("Completed");
}
}
I have created a delegate on the code:-
public partial class Form1 : Form
{
private delegate void DELEGATE();
public Form1()
{
InitializeComponent();
}
private void simulateHeavyWork()
{
Thread.Sleep(100);
...lines of code to perform some search logs operation..
....
}
}
The functionality I want to achieve is that progress bar should report the progress of my function simulateHeavyWork() which is actually using UI thread as it needs to take input from my form controls and update it as well.
Now the problem which is happening is that code is actually calling simulateHeavyWork() and gives the output that is updating ui controls and work is done. (Note: I have used delegate here to avoid error cross controls running on ui thread as my function needs to use UI controls.)
Once that is done, it starts updating progress bar and which is wrong and looks like it calls simulateHeavyWork again and again with the gap of sleep(100).
user3222101, as Andy stated before, you are running simulateHeavyWork() continuously. Moreover, by calling Invoke you are running this method in the UI thread which cause an extra sleep in the UI thread. Basically Invoke uses the message loop (pump) of the Control you use it on (Form1 in that case) and put your delegate to the queue of the UI thread in order to execute. This is not a good practice I think, due to the Sleep() call and time consuming log operations in your simulateHeavyWork() method.
I hope, understand you problem clearly.What I suggest is separation of the time consuming log operations from UI thread. Do not spend the valuable time of UI thread with slow and boring I/O operations. Get the values from the controls (using Invoke in the BackgroundWorker as I will explain below), do whatever you want in BackgroundWorker and update your GUI (again using Invoke) without touching the UI thread for this kind of heavy tasks.
As Andy suggested, you can pass data via the parameter of RunWorkerAsync and you should create a class which can store any data you need (because it accepts only one parameter). However, you can get the values from your Form whenever you need from another thread by using Invoke. Invoke
method also returns the value from your delegate (please see the example at the link below) and this gives you a chance to get the values of your controls on the form. Create a delegate which returns an object of type class that you crated for RunWorkerAsync and use this values in the BackgroundWorker thread. Please, have a look at the example in here.
public static string GetTextThreadSafe(this TextBox box)
{
return GetTextBoxText(box);
}
Also, example uses Func<...> in order to return value.
By this way you can sleep (in BackgroundWorker thread) for a while then get the values from your controls (current values) and do whatever you want (again in BackgroundWorker thread). I think, this improves your code.
From your question: "which is wrong and looks like it calls simulateHeavyWork again and again with the gap of sleep(100)."
Of course it calls. Just look at your code:
for (int i = 0; i <= 100; i++)
{
Delegate del= new DELEGATE(simulateHeavyWork);
this.Invoke(del);
So you are calling simulateHeavyWork 100 times here. And since you've typed Thread.Sleep(100); in the body of simulateHeavyWork - gap between calls is about Sleep(100)

Why would InvokeRequired=False via a Delegate.BeginInvoke?

For what reasons would this.InvokeRequired equal False within InitUIState(), as this new thread is being created via a delegate?
My problem is that my label is never being set and this.BeginInvoke() is never executing, I imagine it's due to the fact InvokeRequired = False.
private delegate void BackgroundOperationDelegate(ViewMode mode);
private BackgroundOperationDelegate backgroundOperationDelegate;
private void FormControlPanel_Load(object sender, EventArgs e)
{
Init();
}
private void Init() {
this.backgroundOperationDelegate = this.InitUIState;
this.backgroundOperationDelegate.BeginInvoke(mode, null, null);
}
private void InitUIState(ViewMode mode)
{
// .. other business logic only here relevant
// to the worker process ..
this.BeginInvoke((MethodInvoker)delegate
{
this.labelProgramStatus.Text = CONSOLE_IDLE_STATUS;
});
}
I use this pattern time and time again, but for some reason, this time it's not executing :P
(and yes there is only one instance of InitUIState() ever being called, that being from the delegate)
Thanks guys.
Images verifying two distinct threads:
http://imgur.com/mq12Wl&X5R7G
http://imgur.com/mq12W&X5R7Gl
Follow up question: Is this an unpreferred way of creating threads? I've just always found it so simple and lightweight. Perhaps I should be using thread.Start() and I will avoid these issues?
Your 2nd BeginInvoke will throw an Exception.
Try
private void InitUIState(ViewMode mode)
{
if (this.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate
{
InitUIState(mode);
});
}
else
{
this.labelProgramStatus.Text = CONSOLE_IDLE_STATUS;
}
}
You are mixing BeginInvoke of Form and Delegate, as both of them have same method name.
Form's method, BeginInvoke calls the method you are requested in the same UI thread, but on a later stage, after processing its own pending UI operations. This is the reason, InvokeRequired will always be false within the Form's BeginInvoke's method.
Delegate's method, BeginInvoke calls the method on a new thread asynchronously in thread pool. And InvokeRequired in delegate's BeginInvoke will always be true.
Invoke and BeginInvoke on delegates are not the same as ISynchronizeInvoke.
Also you need to call EndInvoke when dealing with a delegate.

C# threading issue

To play a bit with threading, delegates and backgroundworkers, I'm putting together a few small applications, I'm having a bit of trouble with one of them.
I've a Windows form, with a textbox, a button and a richttext.
When I press the button, the text in the textbox is used as a paramter to instantiate a class, like this:
public partial class Form1 : Form
{
private BackgroundWorker backgroundWorker;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += new DoWorkEventHandler(worker_DoWork);
backgroundWorker.RunWorkerAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
new Thread((ThreadStart)delegate()
{
this.BeginInvoke((ThreadStart)delegate()
{
foreach (string line in textBox1.Lines)
{
Dig digger = new Dig(line, textBox1.Text);
digger.DomainChecked += new Dig.DomainCheckedHandler(OnUpdateTicker);
string response = digger.GetAllInfo();
richTextBox1.AppendText(response);
Application.DoEvents();
}
});
}).Start();
}
void OnUpdateTicker(string msg)
{
new Thread((ThreadStart)delegate()
{
this.BeginInvoke((ThreadStart)delegate()
{
label4.Text = msg;
Application.DoEvents();
});
}).Start();
}
}
When debugging I run into a 'textBox1.Lines' threw an exception of type 'Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException'
Any tips on how to solve this problem?
First, there is no need to create new threads inside DoWork; the whole idea with the BackgroundWorker is that DoWork is executed on a separate thread. Second, since DoWork is executed on a separate thread and UI controls can be modified only on the UI thread, you need to invoke those updates correctly. So, a rewritten version of worker_DoWork could look like this:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (string line in textBox1.Lines)
{
Dig digger = new Dig(line, textBox1.Text);
digger.DomainChecked += new Dig.DomainCheckedHandler(OnUpdateTicker);
string response = digger.GetAllInfo();
richTextBox1.Invoke((Action) delegate { richTextBox1.AppendText(response); });
}
}
Note how the code does not explicitly spawn any new threads, and also how the AppendText method call is done through a Control.Invoke call, forcing it to execute on the UI thread.
The main reason is that the textbox is not owned by the background thread.
Your UI thread owns all the UI objects, and you're spinning up a background thread when a button is pressed. That background thread should not have access to any UI objects.
If you want the value of the textbox to be used, you'll need to pass it to your background thread another way.
Have a look here for an explanation (and solution).
You can only update controls on the main thread from the main thread itself, unless you explicitly tell your program that it's ok to do, by using the .Invoke method of the control.
From: http://www.albahari.com/threading/part3.aspx
Control.Invoke
In a multi-threaded Windows Forms application, it's illegal to call a method or property on a control from any thread other than the one that created it. All cross-thread calls must be explicitly marshalled to the thread that created the control (usually the main thread), using the Control.Invoke or Control.BeginInvoke method. One cannot rely on automatic marshalling because it takes place too late – only when execution gets well into unmanaged code, by which time plenty of internal .NET code may already have run on the "wrong" thread – code which is not thread-safe.

Categories

Resources