This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
WPF and cross thread operations
I am having trouble with a window in my wpf application displaying, but not updating the view. When placing the cursor over the opened window the loading icon is shown and the window is unresponsive. I am thinking this is likely due to some threading issue I don't have enough experience in seeing.
Here is the setup:
My main program runs on startup and creates and instance of a MainWindow window which implements a custom interface (IPlayer). The main program then runs a process which interracts with IPlayer to accomplish some task, the idea being that the main program requests actions from the MainWindow, which prompts the user for some sort of input and displays the results.
I'll simplify the code for clarity. Assume this program simply runs a sort of chatter bot game.
class MainProgram
{
[STAThread]
static void main(string[] args)
{
MainWindow wdw = new MainWindw();
Game g = new Game(wdw);
wdw.Show();
g.RunGame();
}
}
class Game
{
public IPlayer p;
Game(IPlayer) { this.p = p; }
public RunGame()
{
string r = GetResponse("How was your day?");
...
}
}
public partial class Human_Player : Window, IPlayer
{
public string GetResponse(string Question)
{
ShowQuestion(Question);
string r = GetResponse();
DisplayResponse(r);
return r;
}
...
}
I gave running RunGame() in a separate thread a shot like this:
Thread thread = new Thread(new ThreadStart(game.RunGame));
thread.Start();
but got an InvalidOperationException in response stating "The calling thread cannot access this object because a different thread owns it."
Any help here would be appreciated since I'm pretty new to this stuff. Thanks ahead of time!
EDIT:
Just to clarify, I'm not creating any new threads at the moment. Thus I don't think I'm doing any multi-threading. I'm attempting to run game.RunGame() on the main thread after opening the window. The runGame method consists of a large loop which calls a method on the Human_Player window that changes the UI.
As far as I know there are only two threads:
- Main Thread - MainProgram and Game run here. I think the windows runs here as well but I could be wrong... please clarify
- Rendering Thread - the UI is rendered here.
Argh, this question is asked soooo many times... You cannot update a GUI control from a different thread than the Dispatcher thread associated to the control. You will need to run your update code using Dispatcher.BeginInvoke to update the GUI from the correct thread.
If you are not running the code from a different thread then it's possible that your method is taking too long to execute, thus causing the GUI to hang because the event thread is blocked from accepting user input.
It sounds like your game code is running in a loop and stealing all your UI's processing time. It doesn't sound like you are releasing control to your dispatcher.
Your game code shouldn't loop, it should run an iteration once and then return control to the dispatcher. You need to create a timer control that will call your game code at regular intervals instead.
Related
A while ago we added Python scripting to a Wpf application using IronPython. At first it was only 'slave' in the sense that a script was invoked by a button click for instance and then just ran to completion returning control to Wpf. Later on we added 'master' scripting: the script runs in it's own thread, and controls the rest of the application. That was quite challenging but after a while and with help of existing SO content we got it working, seemingly. Never really used it though, until now, and unfortunately it turns out it does not work properly. Core cause is that although there are two seperate STA threads (the main Wpf one and one for the script), and hence two different Dispatcher instances, the main thread seems to get blocked because the script thread is in a loop waiting for the main thread to complete (in response to a button click processed on the script thread and starting events on the main thread). The whole point of using two threads with seperate ui windows was of course this wouldn't happen. What is going on?
update It is reproducable with minimal code, so I'm linking to that instead of posting pseudo-code here. While creating the code I found that when the window created by the script thread is not embedded (set MainWindow.hostedWin = false) the deadlock does not occur and everything behaves as expected.
in response to comments So there are 3 threads of concern coming into play. Let's call them Python, Ui and Process. Python starts Process and waits for it to complete. Process calls Invoke on Ui. Which shouldn't be doing anything at that point: after all, it's Python that is blocking, not Ui, and the whole point of this construction is that Ui shouldn't have to interact with Python. Well, except that it does somehow. Which is the culprit. In the deadlock, Ui sits at PresentationFramework.dll!System.Windows.Interop.HwndHost.OnWindowPositionChanged(System.Windows.Rect rcBoundingBox) + 0x82 bytes and Process sits at WindowsBase.dll!System.Windows.Threading.DispatcherOperation.DispatcherOperationEvent.WaitOne() + 0x2f bytes and Python is just at Thread.Sleep.
What is going on here, and how to fix it?
I'll keep it short, very few odds that this answer is going to make you happy. It is a three-way deadlock. The most severe one in the interaction between the main thread and PythonThread. This deadlock occurs in the Windows kernel, the NtUserSetWindowPos() call cannot progress. It is blocked, waiting for the WM_LBUTTONUP callback notification on the PythonThread to finish running.
This deadlock is caused by your WpfHwndEmbedHost hack. Turning a top-level window owned by another thread or process into a child window is an appcompat feature that was meant to support Windows 3.x programs. A Windows version that did not yet support threads and where having one task embedding another task's window wasn't a problem. A WPF window isn't exactly much like such a window, to put it mildly. Otherwise a well-known troublemaker, for one the reason that embedding Acrobat Reader in a browser window works so very poorly. Not turning on the WS_CHILD style flag ought to bring relief, but WPF isn't happy about that. Simply setting hostedWin to false solves the problem.
The other deadlock is the one I warned you about, the interaction between the main thread and the ProcessThread. Dispatcher.Invoke() is dangerous, it deadlocks because the main thread is stuck in the kernel. Using Dispatcher.BeginInvoke() solves the problem. Partly, you still have the main thread go catatonic for 5 seconds.
The most severe problem is the kernel lock, that's going to bite in many other ways. You are going to have to keep it a separate window to avoid it. Not good news, I'm sure.
This is a long shot but you might have to implement your own SynchronizationContext to achieve this.
As far as I understand from Andrew Nosenko's answer and his references, it seem that CLR has its own mind about the message pump for the UI thread and it's not actually possible to run two UI threads under one window (BTW, I was able to replicate the issue without IronPython, that seems to be irrelevant here)
Main reference is from cbrumme's WebLog 'Apartments and Pumping in the CLR'
I keep saying that managed blocking will perform “some pumping” when called on an STA thread. Wouldn’t it be great to know exactly what will get pumped? Unfortunately, pumping is a black art which is beyond mortal comprehension. On Win2000 and up, we simply delegate to OLE32’s CoWaitForMultipleHandles service. And before we wrote the initial cut of our pumping code for NT4 and Win9X, I thought I would glance through CoWaitForMultipleHandles to see how it is done. It is many, many pages of complex code. And it uses special flags and APIs that aren’t even available on Win9X.
I must admit I am a little out of my depth here, and might be missing the point completely, so apologies upfront if this might not be an answer to the question at all (Nevertheless it's been a good experience for me, that's for sure).
I have tried using Andrew Nosenko's SynchronizationContext implementation to come up with an example unfortunately without success. Hope it helps you and good luck!
I have delt with similiar problems in my applications where i invoked some UI updates from my heavy load threads and had the same result the UI blocked the thread. I made a solution which i now use in every application though you would need to apply it to your application it works like this:
Apart from the thread you do your work in (and the UI thread) you also need to create another thread, this one will take data from a stack and send it to the UI thread.
Essentialy when you want your UI get a update by your work thread you save the result of your work thread into a List if its more complex data then you would need to create a struct and save all the current data from the thread into the struct and add it to the List (adding data to to the list doesnt require invoke).
Now your second threads runs in a loop and checks at a certain interval if there is something in the List if there is he adds the list elements to your UI.
Here is a sample of how it should work
using System;
using System.Windows;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
namespace nonblock
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private ListBox l1;
private ListBox l2;
private Thread workThread;
private Thread nonBlockThread;
private List<TwoNumbers> list;
private void Form1_Load(object sender, EventArgs e)
{
this.Size = new Size(500,500);
this.FormClosing += (ss, ee) =>
{
workThread.Abort();
nonBlockThread.Abort();
};
l1 = new ListBox();
l1.Dock = DockStyle.Left;
l2 = new ListBox();
l2.Dock = DockStyle.Right;
list = new List<TwoNumbers>();
this.Controls.Add(l1);
this.Controls.Add(l2);
workThread = new Thread(work);
workThread.Start();
nonBlockThread = new Thread(update);
nonBlockThread.Start();
}
private void work()
{
int a = 0;
int b = 0;
int counter = 0;
Random r = new Random();
while (true)
{
a += r.Next();
b += r.Next();
counter++;
if (counter % 10 == 0)
list.Add(new TwoNumbers(a, b));
Thread.Sleep(40);
}
}
private void update()
{
while (true)
{
if (list.Count > 0)
{
for (int a = 0; a < list.Count; a++)
{
l1.Invoke((MethodInvoker)(() => l1.Items.Add(list[0].n1)));
l2.Invoke((MethodInvoker)(() => l2.Items.Add(list[0].n2)));
list.RemoveAt(0);
}
}
Thread.Sleep(1000);
}
}
public class TwoNumbers
{
public int n1 { get; set; }
public int n2 { get; set; }
public TwoNumbers(int a, int b)
{
n1 = a;
n2 = b;
}
}
}
}
I'm new to WPF (and computer science in general) and I was given a small project from my boss where there are 5 tabs, each that go to a different site. After logging in, the user is directed to the website of the 1st tab. In the background, the 4 other tabs should be loading in the background.
Each has the following name: "tabItem1", "tabItem2", "tabItem3", "tabItem4" up to "tabItem5"
Inside each there is a up to "webBrowser5".
I think that I have to use threading to load the pages in the background, but I'm not sure how to implement it. I tried creating 4 different threads in the MainWindow such as:
public MainWindow()
{
InitializeComponent();
Thread thread1 = new Thread(Update1);
thread1.SetApartmentState(ApartmentState.STA);
thread1.Start();
Thread thread2 = new Thread(Update2);
thread2.SetApartmentState(ApartmentState.STA);
thread2.Start();
Thread thread3 = new Thread(Update3);
thread3.SetApartmentState(ApartmentState.STA);
thread3.Start();
Thread thread4 = new Thread(Update4);
thread4.SetApartmentState(ApartmentState.STA);
thread4.Start();
}
private void Update1()
{
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
tabItem2.Focus();
}
);
}
private void Update2()
{
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
tabItem3.Focus();
}
);
}
//...Goes up to Update4
This seems to only focus on the last thread and also it doesn't do it the background. I appreciate any guidance and help. Thanks!
That IS what the dispatcher is doing, operating on the main thread. You told the main thread to set focus because the object is on the main thread.
The problem:
The answer lies in why you must do this. You cannot operate on a windows control in any other thread than the thread it was created on. You also can't create a control in one thread, and set it as a child of a control in another thread.
What this means to you... is that what your boss asked you to do can't be done. The only thing you can do in the background is calculate algorithms. At best, you'll be able to load data, and operate on data, and interpret data, but if you want to have that data be displayed in, or converted into, windows controls, you must do that on the main thread.
The only solution:
However, you can have multiple UIThreads. Which means you can create multiple Windows. So, the must-do alternative is to create windows on separate threads for each tab content, then host the thread-windows on each tab.
Threading windows
Host process window
Cross thread hosting
I do not agree with Xaade, I think you can do what you need using only this code:
Dispatcher.BeginInvoke((Action)(() =>
{
// load the pages
}), DispatcherPriority.Background, null);
That code will be executed in background, so, there you can load every webBrowser you need.
You just need to specify the DispatcherPriority to Background.
I am facing an issue with communication between threads in a C#.NET application.
Hope someone will guide me in the right direction about the possible solutions.
I have an application in C#.NET.It is a windows form application.
My application has two threads - One thread is the main thread (UI thread) and the other one is the child thread. Lets call the child thread the "workerThread"
There is only one form used in the application.Lets call this form the "MainForm"
The child thread is started when the MainForm loads (used the form's "Load" event handler to start the thread)
In the MainForm class, I have a variable named "stopWork" which is a public boolean variable and it serves as a flag to indicate whether the child thread should continue working or should it stop
I have another class (besides the MainForm class) which contains the method that I execute in the the child thread. Lets call this second class the "WorkerClass".
I pass a reference to the current form (the MainForm) into the constructor of the "WorkerClass"
I have a button "stop" in the main form which sets "stopWork" to "true" if its clicked and then calls "workerThread.Join()" to wait for the child thread to finish excecution.
In the child thread, the method "doWork" keeps checking the status of "parentForm.stopWork" inside a for loop. If "stopWork" is set to "true" then the loop breaks and subsequently the method ends.
Now, the issue is, once I am clicking the "stop" button ,the application hangs.
I am pasting parts of the code below so that it is easier to understand :
public partial class MainForm : Form
{
Thread workerThread = null;
ThreadStart workerThreadStart = null;
WorkerClass workerClass = null;
public bool stopWork = true;
/*.......... some code ............*/
private void MainForm_Load(object sender, EventArgs e)
{
workerThreadStart = new ThreadStart(startWork);
workerThread = new Thread(workerThreadStart);
stopWork = false;
workerThread.Start();
}
private void startWork()
{
workerClass = new WorkerClass(this);
}
private void buttonStop_Click(object sender, EventArgs e) //"stop" button
{
if (workerThread != null)
{
if (workerThread.IsAlive == true)
{
stopWork = true;
workerThread.Join();
}
}
}
/*.......... some more code ............*/
}
public class WorkerClass
{
MainForm parentForm=null;
/*......... some variables and code ........*/
public WorkerClass(MainForm parentForm)
{
this.parentForm=parentForm;
}
/* .............. some more code ...........*/
public void doWork()
{
/*.......... some variables and code ...........*/
for(int i=0;i<100000;i++)
{
// ** Here is the check to see if parentForm has set stopWork to true **
if(parentForm.stopWork==true)
break;
/*......... do some work in the loop ..........*/
}
}
/********* and more code .........*/
}
I think I may know where the problem lies.
The problem is in the "doWork" method in the child thread trying to access "stopWork" variable in the parent form when already the parent form is blocked by calling the "workerThread.Join()" method. So ,I think this is a "deadlock" problem.
Am I right in identifying the problem ? Or am I wrong and the problem lies somewhere else ?
In case this is indeed a deadlock, what are the possible solutions to solve this ?
I did a bit of googling and found lots of resources on thread synchronisation and how to avoid deadlocks. But I could not understand how to apply them specifically to my problem.
I would really appreciate any help or guidance on resolving this issue.
Yes, the code you wrote is highly vulnerable to deadlock. The BackgroundWorker class is especially prone to cause this kind of deadlock.
The problem is located in code we can't see in your snippet, the WorkerClass. You are surely doing something there that affects the UI in one way or another, always the primary reason to consider creating a thread in the first place. You probably use Control.Invoke() to have some code run on the UI thread and update a control. Perhaps also to signal that the worker thread is completed and, say, set the Enable property of a button back to true.
That's deadlock city, such code cannot run until the UI thread goes idle, back to pumping its message loop. It will never be idle in your case, it is stuck in Thread.Join(). The worker thread can't complete because the UI thread won't go idle, the UI thread can't go idle because the worker thread isn't finishing. Deadlock.
BackgroundWorker has this problem too, the RunWorkerCompleted event cannot run unless the UI thread is idle. What you need to do is not block the UI thread. Easier said than done, BGW can help you get this right because it runs an event when it completes. You can have this event do whatever you now do in the code past the Thread.Join() call. You'll need a boolean flag in your class to indicate that you are in the 'waiting for completion' state. This answer has relevant code.
Use a BackgroundWorker for this task instead. When you want to stop the task's execution, call the background worker's CancelAsync method.
Generally speaking, rolling your own threading code (on any platform) is a recipe for disaster if you don't have an expert-level understanding of multithreading (and even then it's still dangerous).
I have some code which is been running by a backgroundworker I'd like some specific code which shows some GUI to run in the main thread context (2 reasons 1. it should be blocking 2.I know it's problematic to handle gui controls from a background worker)
I raise an event pass the class and listen to the event in the mainForm from there I check if invoke required and reinvoke. then call the public method of the instance I want to run in the main thread. I have a few questions:
is there any problem to handle data member which are created in the backgoundworker context from the main thread - for both reading and chaning valuse
is there any design pattern for such issue? Idealy I'd like to run any delegate- any return value and a few genric parameters- as func built in delegate- that is problematic because It means if I want to support up to 3 parameters with or without return values I'll have to have 6 events and 6 listeners which actually do the same - does anyone have an idea of how to do this correct?
Thanks!
I just wrote this for a similar question.
I use threads for these kind of stuff.
somewhere in my code:
// Definition
private static Thread TH;
....
// When process starts
TH = new Thread(new ThreadStart(Splash_MyCallBack));
TH.Start();
....
// This method starts the form that shows progress and other data
static private void Splash_MyCallBack()
{
frmLoading FL;
FL = new frmLoading();
FL.ShowDialog();
} /* Splash_MyCallBack*/
// Your process calls Splash_Stop when it is done.
static public void Splash_Stop()
{
TH.Abort();
} /* Splash_Stop*/
frmLoading performs the visual stuff, while in the background I have a very processor-intensive task.
My process reports to an interface its progress. frmLoading implements that interface so it is aware of it and can show whaever it is needed (2 progress bars in my case)
Tha only catch is, frmLoading must have this in the constructor:
Control.CheckForIllegalCrossThreadCalls= false;
which may be risky in some scenarios (not my case).
I think that the fact that the main process calls an interface to update progress, and the real interface consumes that is a pattern.
Hope this helps, I can add more stuff if you like.
Regards,
To answer your first question:
There shouldn't be any problems handling data created in the background worker. I've done it in a couple of applications and not had any issues.
I have a Windows Form Application (Form1) that allow the user to open another Forms (FormGraph). In order to open the FormGraph App I use a thread that open it.
Here is the code that the thread is running:
private void ThreadCreateCurvedGraph()
{
FormGraph myGraph = new FormGraph();
myGraph.CreateCurvedGraph(...);
myGraph.Show();
}
My problem is that myGraph closed right after it's open.
1) Does anyone know why this is happening and how to make myGraph stay open?
2) After the user closed myGraph, How do I terminate the thread?
Many thanks!
The problem is not in the posted snippet. You'll need to start a new message loop with Application.Run() or Form.ShowDialog(). You'll also need to take care of thread properties so it is suitable to act as a UI thread. For example:
Thread t = new Thread(() => {
Application.Run(new Form2());
// OR:
//new Form2().ShowDialog();
});
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
There are some awkward choices here. The form cannot be owned by any form on your main thread, that usually causes Z-order problems. You'll also need to do something meaningful when the UI thread's main form is closed. Sloppily solved here by using IsBackground.
Windows was designed to support multiple windows running on one thread. Only use code like this if you really have to. You should never have to...
The main problem you ahve is that you do not establish a message pump in the new thread.
Check
Run multiple UI Threads
for a good overview how to run a high perforamnce user interface using multiple threads (one per form / group of forms).
What you basically miss is the call to Application.Run to set up the message pump on the separate UI thread.
I think once the last form of a message pump closes - it will dispose itself and end.
Note that all this ASSUMES you WANT to open the window in a separate UI thread... otherwise you need to invoke back to the main UI thread for the creation and all manipulation of the window, so it gets attached to the existing message pump. There are GOOD cases for both - one keeps thigns simple, the other allows a LOT more performance as every window has a separate message pump and can thus act individually - this is for example used a lot in trading applications which may need to update graphs on a number of screens and havea bottleneck if running single threaded in the UI.
As a rule of thumb you should avoid manipulating the UI from threads (creating a form is a sort of manipulation to the UI). You should always manipulate the UI from the main thread.
The form is closing because the thread has finished and is therefore free'd along with its resouces (the form). To make the thread stay running you need a loop
e.g.
private void ThreadCreateCurvedGraph()
{
FormGraph myGraph = new FormGraph();
myGraph.CreateCurvedGraph(...);
myGraph.Show();
while (myGraph.IsOpen)
{
//process incoming messages <- this could be fun on a thread....
}
}
You'll need a method of setting IsOpen (like a timeout or a button) and obviously you'll need to actually create IsOpen as a property of the form and set it to true when the form is created.
I'll add here the same as other users... You should have a good reason for not using the main thread.
If it takes a while to prepare the data for the form, you can do that in a separate thread to keep the application responsive. When the data is ready you can return the object to the main thread an let it show it.
You should declare a variable for the object in the form rather than locally in the method, so that it survives when you exit the thread.
When you are ready to show the form, you can use the Invoke method to make a method call that will be executed in the main thread.
do not create and show forms in non-main thread. do it in main form thread.
Or do this:
private void ThreadCreateCurvedGraph()
{
FormGraph myGraph = new FormGraph();
myGraph.CreateCurvedGraph(...);
Application.Run(myGraph);
}
but first version is better
Why are you creating a form on a new thread? There are times you need to use a new thread but other times you can use form.ShowDialog() on the main thread.
What about if you show the form as if it was a Dialog? You can use
private void ThreadCreateCurvedGraph()
{
FormGraph myGraph = new FormGraph();
myGraph.CreateCurvedGraph(...);
myGraph.ShowDialog();
}
This way the call will block until the myGraph form is closed. As you have the myGraph created on a separated thread calling the blocking ShowDialog should block only that thread.
Perhaps this is garbage collection:
After ThreadCreateCurvedGraph() exits, myGraph goes out of scope and closes.
You need to organise a way of the thread to hold on to the instance and wait (using a blocking wait) for it to close.
Edit: For instance add:
Application.Run(myGraph)
to the end of the method.
(See comments from TomTom)