Thread calling problems - c#

I'm a bit of a newbie at this but I am trying to get the UI on a Reversi game to run on a different thread to the move selection part but I am having some trouble calling the thread on the button click
private void playerMoveOKButton_Click(object sender, EventArgs e)
{
ReversiT.Invoke();
}
public void ReversiT() {...}

If you're trying to create a new thread, you can do something like this:
Thread thread = new Thread(ReversiT);
thread.Start();
Invoke is used for a different purpose though. It is used to run a method on a specific thread (for instance, if you run a piece of code on a separate thread but want to make UI changes, you will want to use Invoke to make those changes on the UI thread)

I would create a BackgroundWorker to handle everything for me, setting it's DoWork event to call your move method (making sure that your move method doesn't touch the UI, or if it has to, invoking the controls on the UI thread).
I'd also set up a method to update the UI on the BackgroundWorker's RunWorkerCompleted event.
Now on your button click event above, call the BGW's RunWorkerAsync() method.

You can not invoke a method like that. You can only invoke delegates. Also, calling Invoke doesn't spawn a new thread.
You can read this tutorial about delegates, and this one about threads. Also, your question leaves much space for discussion:
What do you expect from using threads?
Have you considered different options for doing background work?
etc.

Use following
this.Invoke(ReversiT);

I think you need to think about that you are actually trying to achieve here. Running code on a separate thread in a UI is a technique used to stop the UI from hanging. However, some tasks simply have to occur on the UI thread and so can't be run from another thread.
You need to break your logic out such that you can identify which parts need to run on the UI thread (anything that interacts with a control on your UI) and thus anything that can run on a separate thread.
You would end up with code like (as an example):
private void playerMoveOKButton_Click(object sender, EventArgs e)
{
//thread is merely used as an example
//you could also use a BackgroundWorker or a task
var thread = new Thread(NonUiLogic);
thread.Start();
}
private void NonUiLogic()
{
...
//execute logic that doesn't touch UI
...
BeginInvoke(ReversiT);
}
public void ReversiT() {...}
Once you have been through that exercise you may find that there is actually very little that can happen outside of the UI thread and so you really have nothing to gain from using threads.

Related

How to call Same event Handler with multiple class object in Windows form C# [duplicate]

I have a windows forms application
on which I need to use a for loop having a large number of Remote Calls around 2000 - 3000 calls,
and while executing the for loop, I loose my control on form and form controls, as it becomes a large process and some time it shows "Not Responding" but if I wait for a long it comes back again, I think I need to use some threading model for that, is there any idea, how can I proceed to solve the issue?
You need to perform the long running operation on a background thread.
There are several ways of doing this.
You can queue the method call for execution on a thread pool thread (See here):
ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod));
In .NET 4.0 you can use the TaskFactory:
Task.Factory.StartNew(() => YourMethod());
And in .NET 4.5 and later, you can (and should, rather than TaskFactory.StartNew()) use Task.Run():
Task.Run(() => YourMethod());
You could use a BackgroundWorker for more control over the method if you need things like progress updates or notification when it is finished. Drag the a BackgroundWorker control onto your form and attach your method to the dowork event. Then just start the worker when you want to run your method. You can of course create the BackgroundWorker manually from code, just remember that it needs disposing of when you are finished.
Create a totally new thread for your work to happen on. This is the most complex and isn't necessary unless you need really fine grained control over the thread. See the MSDN page on the Thread class if you want to learn about this.
Remember that with anything threaded, you cannot update the GUI, or change any GUI controls from a background thread. If you want to do anything on the GUI you have to use Invoke (and InvokeRequired) to trigger the method back on the GUI thread. See here.
private voidForm_Load(object sender, EventArgs e)
{
MethodInvoker mk = delegate
{
//your job
};
mk.BeginInvoke(callbackfunction, null);
}
private void callbackfunction(IAsyncResult res)
{
// it will be called when your job finishes.
}
use MethodInvoker is the easiest way.
Obviously, you need to use background threads. I suggest you read this free e-book.

Calling thread cannot access this object

In my wpf application I have added a piece of code in the button click as below:
private void btn_convert_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread(new ThreadStart(WorkerMethod));
t.SetApartmentState(ApartmentState.MTA);
t.IsBackground = true;
t.Start();
}
Inside my WorkerMethod() method I have some code like the line below:
btn_convert.Content = "Convert";
When it reaches to this line it throws the exception as the calling thread cannot access this object because a different thread owns it.
I dont want to use Dispatcher as it freezes the UI.. UI should be responsive so I have not opted for Dispatcher invoke or BeginInvoke.
Please give me your valuable suggestions.
I dont want to use Dispatcher as it freezes the UI.. UI should be responsive so i am not opted for Dispatcher invoke or BrginInvoke.
That just shows that you've used the dispatcher badly.
You must access the UI from the UI thread. That doesn't mean your whole WorkerMethod needs to run on the UI thread, but this line:
btn_convert.Content = "Convert";
definitely does. So you might want to keep your current code for starting a thread (do you really need to set the apartment state though) but change any code accessing the UI to use the dispatcher. For example:
Action setButtonContentAction = () => btn_convert.Content = "Convert";
Dispatcher.BeginInvoke(setButtonContentAction);
Alternatively, depending on what your WorkerThread is doing - and if you're using C# 5 - you might want to use the new async features. That can make it easier to keep UI work on the UI thread, but it does depend on what else is going on.
UI changes can only be applied by the main thread. You can check if the main thread call is necessary:
if (btn_convert.InvokeRequired)
{
btn_convert.Invoke((MethodInvoker)(() => btn_convert.Content = "Convert"));
}

BackgroundWorker In Form.Load event

I'm working in a c# windows application with vs2010 and a local database.In one of my forms i use a BindingNavigator with a group of textboxes filled by the database and a ReporViewer. I've added a background worker in order to fill the table adapters in case there are a lot of records in the database.
The problem is that the way I'm using the background worker when i debug my app i cannot see any data in the textboxes, otherwise when i run my app it's working fine. I know that this is a case of accessing the UI on a non-UI thread and it is wrong. Is there a another way around it?Thank you in advance.
Here is the code I'm using:
private void Client_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
this.clientTableAdapter.Fill(this.database1DataSet.Client);
this.projectTableAdapter.Fill(this.database1DataSet.Project);
if (InvokeRequired)
{
this.Invoke(new MethodInvoker(this.reportViewer1.RefreshReport));
return;
}
}
Typically, a background worker returns on the same thread, and would actually throw an exception about the non-UI thread. However, this might be eaten in your case. You should be using the RunWorkerCompleted event for items that are to happen after your main work is done, especially when looking to update the UI. And, this should return to the same thread it was called from (UI in your case) as mentioned above.
So, I would move your UI processing code (RefreshReport) into a new method set up for the RunWorkerCompleted.
However, my suggestion would be to take a look at the Task Parallel Library. It ends up making code much cleaner and easier to debug IMO.
Example (rough and may not compile due to the nulls, but you can get the jist :)):
var task = Task.Factory.StartNew(()=>{//Do Async Stuff});
task.ContinueWith((previousTask)=>{//Do your UI Stuff}, null, null,
TaskScheduler.FromCurrentSynchronizationContext);
//The FromCurrentSync makes sure the method returns
//to the same thread (UI in this case) that it started
I know that is not a direct answer, but more of a suggestion towards what I would consider a cleaner, more debuggable approach.

C# Multi threading- Move objects between threads

i am working with a winforms control that is both a GUI element and also does some internal processing that has not been exposed to the developer. When this component is instantiated it may take between 5 and 15 seconds to become ready so what i want to do is put it on another thread and when its done bring it back to the gui thread and place it on my form. The problem is that this will (and has) cause a cross thread exception.
Normally when i work with worker threads its just with simple data objects i can push back when processing is complete and then use with controls already on the main thread but ive never needed to move an entire control in this fashion.
Does anyone know if this is possible and if so how? If not how does one deal with a problem like this where there is the potential to lock the main gui?
You don't need to lock the GUI, you just need to call invoke:
Controls in Windows Forms are bound to
a specific thread and are not thread
safe. Therefore, if you are calling a
control's method from a different
thread, you must use one of the
control's invoke methods to marshal
the call to the proper thread. This
property can be used to determine if
you must call an invoke method, which
can be useful if you do not know what
thread owns a control. ref
Here is how it looks in code:
public delegate void ComponentReadyDelegate(YourComponent component);
public void LoadComponent(YourComponent component)
{
if (this.InvokeRequired)
{
ComponentReadyDelegate e = new ComponentReadyDelegate(LoadComponent);
this.BeginInvoke(e, new object[]{component});
}
else
{
// The component is used by a UI control
component.DoSomething();
component.GetSomething();
}
}
// From the other thread just initialize the component
// and call the LoadComponent method on the GUI.
component.Initialize(); // 5-15 seconds
yourForm.LoadComponent(component);
Normally calling the LoadComponent from another thread will cause a cross-thread exception, but with the above implementation the method will be invoked on the GUI thread.
InvokeRequired tells you if:
the caller must call an invoke method
when making method calls to the
control because the caller is on a
different thread than the one the
control was created on.
ref
Update:
So if I understand you correctly the control object is created on a thread other than the GUI thread, therefore even if you were able to pass it to the GUI thread you still won't be able to use it without causing a cross-thread exception. The solution would be to create the object on the GUI thread, but initialize it on a separate thread:
public partial class MyForm : Form
{
public delegate void ComponentReadyDelegate(YourComponent component);
private YourComponent _component;
public MyForm()
{
InitializeComponent();
// The componet is created on the same thread as the GUI
_component = new YourComponent();
ThreadPool.QueueUserWorkItem(o =>
{
// The initialization takes 5-10 seconds
// so just initialize the component in separate thread
_component.Initialize();
LoadComponent(_component);
});
}
public void LoadComponent(YourComponent component)
{
if (this.InvokeRequired)
{
ComponentReadyDelegate e = new ComponentReadyDelegate(LoadComponent);
this.BeginInvoke(e, new object[]{component});
}
else
{
// The component is used by a UI control
component.DoSomething();
component.GetSomething();
}
}
}
Without knowing too much about the object. To avoid cross thread exceptions, you can make the initial thread invoke a call (Even if you are calling from a thread).
Copied and pasted from one of my own applications :
private delegate void UpdateStatusBoxDel(string status);
private void UpdateStatusBox(string status)
{
listBoxStats.Items.Add(status);
listBoxStats.SelectedIndex = listBoxStats.Items.Count - 1;
labelSuccessful.Text = SuccessfulSubmits.ToString();
labelFailed.Text = FailedSubmits.ToString();
}
private void UpdateStatusBoxAsync(string status)
{
if(!areWeStopping)
this.BeginInvoke(new UpdateStatusBoxDel(UpdateStatusBox), status);
}
So essentially the threaded task will call the "Async" method. Which will then tell the main form to begininvoke (Actually async itself).
I believe there is probably a shorter way to do all of this, without the need for creating delegates and two different methods. But this way is just ingrained into me. And it's what the Microsoft books teach to you do :p
The BackgroundWorker class is designed for exactly this situation. It will manage the thread for you, and let you start the thread, as well as cancel the thread. The thread can send events back to the GUI thread for status updates, or completion. The event handlers for these status and completion events are in the main GUI thread, and can update your WinForm controls. And the WinForm doesn't get locked. It's everything you need. (And works equally well in WPF and Silverlight, too.)
The control must be created and modified from the UI thread, there's no way around that.
In order to keep the UI responsive while doing long-running initialization, keep the process on a background thread and invoke any control access. The UI should remain responsive, but if it doesn't, you can add some wait time to the background thread. This is an example, using .Net 4 parallel tools: http://www.lovethedot.net/2009/01/parallel-programming-in-net-40-and_30.html
If interaction with the specific control being initialized can't be allowed until initialization finishes, then hide or disable it until complete.

WinForm Application UI Hangs during Long-Running Operation

I have a windows forms application
on which I need to use a for loop having a large number of Remote Calls around 2000 - 3000 calls,
and while executing the for loop, I loose my control on form and form controls, as it becomes a large process and some time it shows "Not Responding" but if I wait for a long it comes back again, I think I need to use some threading model for that, is there any idea, how can I proceed to solve the issue?
You need to perform the long running operation on a background thread.
There are several ways of doing this.
You can queue the method call for execution on a thread pool thread (See here):
ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod));
In .NET 4.0 you can use the TaskFactory:
Task.Factory.StartNew(() => YourMethod());
And in .NET 4.5 and later, you can (and should, rather than TaskFactory.StartNew()) use Task.Run():
Task.Run(() => YourMethod());
You could use a BackgroundWorker for more control over the method if you need things like progress updates or notification when it is finished. Drag the a BackgroundWorker control onto your form and attach your method to the dowork event. Then just start the worker when you want to run your method. You can of course create the BackgroundWorker manually from code, just remember that it needs disposing of when you are finished.
Create a totally new thread for your work to happen on. This is the most complex and isn't necessary unless you need really fine grained control over the thread. See the MSDN page on the Thread class if you want to learn about this.
Remember that with anything threaded, you cannot update the GUI, or change any GUI controls from a background thread. If you want to do anything on the GUI you have to use Invoke (and InvokeRequired) to trigger the method back on the GUI thread. See here.
private voidForm_Load(object sender, EventArgs e)
{
MethodInvoker mk = delegate
{
//your job
};
mk.BeginInvoke(callbackfunction, null);
}
private void callbackfunction(IAsyncResult res)
{
// it will be called when your job finishes.
}
use MethodInvoker is the easiest way.
Obviously, you need to use background threads. I suggest you read this free e-book.

Categories

Resources