I have a UserControl with a tree on it. It uses multithreading to add nodes to it. I have a function called Expand which I need to execute after filtering completed and since I'm a newbie with multithreading I'm not sure how to do that. Here's my code:
class MyClass : UserControl
{
private Thread nThread;
private bool searchLoadCompleted = false;
private void Filter()
{
ClearTree();
this.nThread = new Thread(new ParameterizedThreadStart(AddFilteredResultsToTree));
this.nThread.IsBackground = true;
this.nThread.Start(someParameter);
}
private void AddFilteredResultsToTree(int someParameter)
{
myTree.Invoke(new MethodInvoker( ()=> this.searchLoadCompleted = false ));
myTree.Invoke(new MethodInvoker( ()=> AppendNode(......) ));
myTree.Invoke(new MethodInvoker( ()=> this.searchLoadCompleted = true ));
}
private void Expand()
{
}
}
I tried to add nThread.Join() into Expand() but it got stuck indefinitely. What should I do?
If the singlethreaded version of this is:
ClearTree();
AddFilteredResultsToTree(someparameter);
Expand();
Don't bother going multithreading, just do it on the same thread. The point of using multithreading there would be to let the main thread handle UI events, if you join the thread then you're basically just launching a background thread while freezing (not doing any work) in the main thread. Note that by calling Invoke you're actually delegating the execution of AddFilteredResultsToTree to the main thread anyway.
I'd suggest you simply call Expand from AddFilteredResult and use the Dispatcher to update the UI if needed or.
Another way to go (best in my opinion) would be to use the Async Pattern for this (example and tutorial here), and then on the AsyncCallback update the UI.
Calling Invoke will block both the GUI thread and your worker thread so there won't be any performance improvement over code without a worker thread.
Related
I faced with one interesting moment when working with multithreading.
I have two threads. In main thread I create layout and add to it control,in second thread I create another control and add to the same layout. It works fine, but second thread works a bit longer then main. So main should wait for second thread.I use for this AutoResetEvent and got DeadLock. Below I describe code what I use:
private static AutoResetEvent resetEvent = new AutoResetEvent(false);
private BackgroundWorker backgroundAdvancedViewWorker = new BackgroundWorker();
private delegate void ShowViewDelegate();
public void Run()
{
MainGeneralReportForm mainForm = ObjectFactory.GetOrCreateView<IMainGeneralReportForm>();
backgroundSimpleViewWorker.RunWorkerAsync(_mainForm);
GeneralReportFormatView formatView =
ObjectFactory.ShowView<IGeneralReportFormatView>()
resetEvent.WaitOne();
DoSomething(advancedSearchView);
}
private void backgroundAdvancedViewWorker_DoWork(object sender, DoWorkEventArgs e)
{
MainGeneralReportForm mainForm = e.Argument as MainGeneralReportForm;
if (mainForm!= null && mainForm.InvokeRequired)
{
mainForm.BeginInvoke(new ShowViewDelegate(() =>
{
advancedSearchView =
ObjectFactory.ShowView<IGeneralReportAdvancedSearchView>();
resetEvent.Set();
}));
}
}
}
If main thread doesn't wait for second thread, the application throws NullReferenceException.
Is exist any solution or workaround of this problem?
You block main thread by resetEvent.WaitOne(); and at the same time trying to schedule work item back to main thread with BeginInvoke (which indeed can't run as main thread is waiting).
Not sure what right fix would be, but blocking on main thread is not really an option.
Maybe some "state" field on the form may be enough. Or maybe running DoSomething(advancedSearchView); from BeginInvoke callback (instead of resetEvent.Set();).
Note: if you are on 4.5 you can consider using async/await instead of manual threading.
I'm thinking of a simple way of reacting on task finishing its work. I came up with the following solution (paste it to WinForms application with a single button to test):
public partial class Form1 : Form
{
private Thread thread;
public void DoFinishWork() {
// [4]
// UI thread - waiting for thread to finalize its work
thread.Join();
// Checking, if it really finished its work
MessageBox.Show("Thread state: " + thread.IsAlive.ToString());
}
public void DoWork() {
// [2]
// Working hard
Thread.Sleep(1000);
}
public void FinishWork() {
// [3]
// Asynchronously notifying form in main thread, that work was done
Delegate del = new Action(DoFinishWork);
this.BeginInvoke(del);
// Finalizing work - this should be switched
// at some point to main thread
Thread.Sleep(1000);
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
// [1]
// Schedule the task
ThreadStart start = new ThreadStart(DoWork);
// Schedule notification about finishing work
start += FinishWork;
thread = new Thread(start);
thread.Start();
}
}
This is meant to be a simple cancel scenario, so there will be only one thread, which will be running in parallel to the UI thread.
Is there a simpler (or more thread-safe) way of implementing this kind of notification for the Thread?
Please take into consideration two facts:
The only way i can terminate the thread is to Abort it (that's because I have no control over what is being done in the thread - 3rd party code)
Thus, I cannot use BackgroundWorker, because it only provides way of graceful termination.
Is there a simpler (or more thread-safe) way of implementing this kind of notification for the Thread?
Yes, use the TPL and let the framework worry about managing the thread
Task.StartNew(() => {
// do some stuff
}).ContinueWith((task) => {
// do some stuff after I have finished doing some other stuff
});
Or alternatively, since you are working with WinForms, use a BackgroundWorker and handle the RunWorkerCompleted event.
I mistook your notion of kill for cancel - there is no reliable way of actually killing a thread in .NET, even the documentation suggests that using Abort is more or less a gamble and gives absolutely no guarentees that the thread will actually be killed. Also, it will leave the thread and, as a consequence, the application in an unpredictable state so if you are willing to take that risk then that's up to you.
One alternative is to simply let the thread play out but just ignore the results, depending on the size of the task it might not be that big a deal.
Although you need Abort to kill the thread, you can still use the TPL. You could start that thread within the task, and wait for it as well as for an CancellationToken. When the task is cancelled before the thread finishes, you can call Abort on the thread.
It would look something like that:
// In your class:
ManualResetEvent threadFinished = new ManualResetEvent(false);
// In your calling function (button1_Click):
Task.Run( () => {
ThreadStart threadStart = new StreadStart(DoWork);
threadStart += () => { threadFinished.Set(); }
Thread thread = new Thread(threadStart);
threadFinished.Reset();
thread.Start();
WaitHandle waitCancel = cancellationToken.WaitHandle;
int waited = WaitHandle.WaitAny( new WaitHandle[]{ waitCancel, threadFinished } );
if (waited == 0 && cancellationToken.IsCancellationRequested)
thread.Abort();
else
thread.Join()
});
I have faced with a problem of threads synchronization. My presenter analyzes some sensors and update UI form. I moved updating code into separate thread. It works fine, but if the user stops presenter when it is updating the view, the software freezes - I found that it happens when view.UpdateUI working (it just set some labels using Invoke). Where my problem is? I use compact framework 3.5 and Windows CE 5
using System.Threading;
class MyPresenter
{
UserControl view;
private Thread thread;
private ManualResetEvent cancelEvent;
public void Start()
{
cancelEvent = new ManualResetEvent(false);
thread = new Thread(UpdateView) { IsBackground = true };
thread.Start();
}
public void Stop()
{
if (thread != null) {
cancelEvent.Set();
thread.Join();
thread = null;
}
}
private void UpdateView()
{
while (cancelEvent.WaitOne(1000, false) == false) {
// analyze something
view.UpdateUI(...);
}
}
}
Don't update the UI thread directly from within a worker thread. Use a delegate instead.
For example: How to update the GUI from another thread in C#?
If your background thread is blocked calling your UI (via Control.Invoke), and then your UI thread is blocked calling your Stop method with its thread.Join() you've got yourself a classic fatal embrace. You should get rid of the Join and instead have the background thread raise one last event / notification when the Stop completes so the UI can deal with that (enable/disable buttons etc).
I have code that runs in a different thread than the UI's one, and it has to create a control (windows forms). However, I don't have a reference to any control from the UI (that way, I could use myControl.Invoke( methodThatAddsControlToUI ) ). Is there a way to do it in the .net compact framework?
I would be interested in a solution that doesn't use references to other controls, if possible (tracking all created forms, for example, would not be a good workaround, as my code will be in a library). In the full framework version, there is the Application.OpenForms property, but this doesn't exit in the CF.
EDIT:
The main purpose of this is calling a method on the UI thread:
class Worker
{
public MyMethod()
{
// I need to call a method on the UI (this code doesn't run in the UI thread),
// but I don't have any field in this object holding an UI control
// value. So, I can't write myControlField.Invoke(...),
// but I still need to call a method on the UI thread
}
}
Any suggestions?
From a library there's really no way to guarantee your thread context, so your safest bet is to have the consume provide the invoker and leave it to them to ensure it was created in the proper context. Something like this pattern:
class Foo
{
private Control m_invoker;
public Foo()
: this(null)
{
}
public Foo(Control invoker)
{
if (invoker == null)
{
// assume we are created on the UI thread,
// if not bad things will ensue
m_invoker = new Control();
}
else
{
m_invoker = invoker;
}
}
public void Bar()
{
m_invoker.Invoke(new Action(delegate
{
// do my UI-context stuff here
}));
}
}
I'm sorry if this isn't a real answer, but I think it may help:
The reason why WinForms has this approach -- using a Control or Form reference to access a Invoke method that enables you to run code on the UI Thread -- is that the only reason you should have to run a code in the UI Thread is if you are going to write/change the state of UI components.
Of course, if you are going to do that, you must have a reference to a UI component. So you'd have access to its Invoke method. I cannot think of any other reason you'd have to access the UI thread from a component other than to modify a visual element.
It must be invoke ... But invoke have to wait still main thread i mean you not get error this way but this is not exacly working parallel if you want to go more than one process at same time just create more then one thread
Thread thread = new Thread(new delegate_method(method));
thread.start ();
Thread thread2 = new Thread(new delegate_method(method2));
thread.start ();
handle two process same time
void method ()
{
//do something here -- working background Remember can not control any UI control from here
finish_thread()
}
void method2 ()
{
//do something here -- working background Remember can not control any UI control from here
finish_thread()
}
void finish_thread()
{
if(invoke.Required)
{
//Here you have to call delegate method here with UI
BeginInvoke(new delegate_method(finish_thread));
}
else
{
//Now you can control UI thread from here and also you finished background work
//Do something working with UI thread
textBox.Text = "";
}
}
//Declare this in class
public delegate void delege();
//Write this lines when you want to background thread start
Thread thread = new Thread(new ThreadStart(() => {
//Do what you what with backgorund threading , can not use any interface comand here
BeginInvoke(new delege(() => {
//Do here any main thread thread job,this can do interface and control jobs without any error
}));
}));
thread.Start();
We have a silverlight application which uses a dispatcher and I would appreciate any help explaining what the following codes does? (unfortunately the developer who wrote the code has left).
So what we have is the following:
public class ABC
{
private Dispatcher dispatcher;
private Thread threadRunner;
public void ABC()
{
threadRunner= new Thread(ThreadRunnerMethod)
{
IsBackground = true,
ApartmentState = ApartmentState.STA
};
threadRunner.Start();
}
private static void ThreadRunnerMethod()
{
Dispatcher.Run();
}
public void MainMethod()
{
dispatcher = Dispatcher.FromThread(threadRunner);
dispatcher.Invoke(new Action(() =>
// "DO SOME WORK WITH A COM OBJECT"
));
}
}
I have some basic experience with threading but I have no idea how this all works?
JD
It's the equivalent of Control.Invoke in Windows Forms, basically - it's just been separated into its own object.
As I understand it, Dispatcher.Run will basically start an event loop, and you can marshall calls into that event loop using Dispatcher.Invoke. Dispatcher.FromThread finds the Dispatcher object which is responsible for a given thread - so in this case, it finds the event loop running in the new thread.
So in your code, the delegate created with the lambda expression will execute in the newly created thread.