I encountered a to me not understandable error caused by using Dispatcher.BeginInvoke
within a multi-threaded application.
My program contains a List
of objects through which I loop using multiple threads and perform some calculations.
I have simplified (and slightly modified) my code structure to the very bare essentials, so it will hopefully be easier to understand:
public class Foo
{
public void DoCalc()
{
//do calculations
}
}
public class Foo2
{
public Foo foo = new Foo();
public Ellipse ellipse;
}
public partial class MainWindow : Window
{
List<Foo2> myList = new List<Foo2>();
List<Tuple<int, int>> indicesList = new List<Tuple<int, int>>();
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 10; ++i)
myList.Add(new Foo2 { ellipse = new Ellipse() });
for (int i = 10; i < 20; ++i)
myList.Add(new Foo2());
indicesList.Add(new Tuple<int, int>(0, 9));
indicesList.Add(new Tuple<int, int>(10, 19));
}
private void OnStart(object sender, RoutedEventArgs e)
{
foreach (var t in indicesList)
ThreadPool.QueueUserWorkItem(new WaitCallback(Loop), t);
}
private void Loop(object o)
{
Tuple<int, int> indices = o as Tuple<int, int>;
for(int i = indices.Item1; i <= indices.Item2; ++i)
{
myList[i].foo.DoCalc();
if (myList[i].ellipse == null)
continue;
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => myList[i].ellipse.Fill = Brushes.Black));
}
}
}
The first half of items in myList
has ellipse
point to actual objects, while the second half points to null
. Within Loop
I check at every iteration if ellipse
is null
and skip that iteration if necessary. What is weird is that in the second thread where all ellipses point to null, the program still ends up calling the BeginInvoke action on the first item (index 10), causing the program to crash, due to a null reference exception.
If I put a breakpoint on the line myList[i].foo.DoCalc();
and go through the program slowly step by step, no error occurs. Also when I change BeginInvoke
to Invoke
no error occurs.
As I understand, BeginInvoke works asynchronously by sending a request to the Dispatcher to be performed at some point, while Invoke blocks the calling thread until the Dispatcher has performed the request. However, since I neither access the same elements in the two loops, nor do I change anything about the list itself, so I don't understand how multithreading or the asynchronous nature of BeginInvoke could in any way interfere with what I am doing here.
Unfortunately, I have only found BeginInvoke errors connected with List
s when adding or removing items on SO, however, nothing where an error occurs when all threads seem to access different items at all times. If my code has some fundamental issues that I do simply not understand (which might cause my program to actually not function), then please clear this up for me or send me a link to an answer, I couldn't find. I have been stuck with this issue for a whole day now!