Collection was modified; enumeration operation may not execute - c#

i wrote this code to create a chart(by using wpf toolkit charting) but I receive this error,
private void Window_Loaded(object sender, RoutedEventArgs e)
{
LoadLineChartData2();
}
private void LoadLineChartData2()
{
time= new Timer(10);
time.Elapsed += new ElapsedEventHandler(time_Elapsed);
time.Start();
}
Timer time;
List<KeyValuePair<double, int>> list = new List<KeyValuePair<double, int>>();
int index = 0;
void time_Elapsed(object sender, ElapsedEventArgs e)
{
list.Add(new KeyValuePair<double,int>(1.0/int.Parse(e.SignalTime.Second.ToString()),index++));
this.Dispatcher.Invoke(new Action(()=> {
((System.Windows.Controls.DataVisualization.Charting.LineSeries)mcChart.Series[0]).ItemsSource = list;
if (index>200)
{
time.Stop();
}
}));
}
erorr: Collection was modified; enumeration operation may not execute.
what is the error and how I can dynamically add points??

Your list object is not thread-safe. I am assuming you are using a re-entrant timer as well. Your code will be executing in a new thread every 10 milliseconds, which presumably causes the List<> to be changed each time.
Try changing the time/tick (to maybe 100ms) and see if your problem goes away. You should also use a ConcurrentBag<T> in place of the list, which will support concurrent adds and iterations. Though I am going to add as an editorial comment, what you are trying to do in your code does not make sense to me.

Related

How to prevent ListView sorting from blocking the program

I have a list with hundreds items,
when I try to sort the items, it always blocking my program.
It' so too annoying.
I try to use Task.Run(), It doesn't work.
private void resultListView_ColumnClick(object sender, ColumnClickEventArgs e)
{
// doesn't work
Task.Run(() => ListViewOperate((ListView)sender, ListViewOP.SORT));
// doesn't work
resultListView.BeginUpdate();
ListViewOperate((ListView)sender, ListViewOP.SORT);
resultListView.EndUpdate();
}
private delegate void ListViewOperateDelegate(System.Windows.Forms.ListView liv,
ListViewOP op);
private void ListViewOperate(System.Windows.Forms.ListView liv, ListViewOP op)
{
if (liv.InvokeRequired)
{
var addDele = new ListViewOperateDelegate(ListViewOperate);
liv.Invoke(addDele, new object[] { liv, op});
}
else
{
if (op == ListViewOP.SORT)
{
liv.BeginUpdate();
liv.Sort();
liv.EndUpdate();
}
}
}
The trick you are trying to use, doesn't work here, because you are starting the
ListViewOperator on a thread/task but the callback checks if it is started on the UI thread. If it isn't on the UI thread, invoke it on the UI thread. So what benefits did you gain? none..
You should check the Virtual Mode. With the virtual mode you are able to sort it (a copy) of the list on a task/thread and then swap the list "variable" and trigger the listview to refresh it self.
Here is an Example

Thread Safety C# List<T>

I know of and have used the System.Collections.Concurrent.ConcurrentBag<T> for building thread safe code in the past. I have some legacy code that I'm trying to thread to increase performance however there is a non static List object that is being written with different sources of data. All of the writing is being done prior to any reading of the list and my initial tests show that multiple threads appear to write to the object without any issues.
Sample Windows App
Does a non static C# List object have thread safety for writing across multiple threads prior to reading? How can this be tested?
BackgroundWorker backgroundWorkerA, backgroundWorkerB;
System.Threading.ManualResetEvent manualReset;
List<string> _shardList = new List<string>(0);
public UserControl1()
{
InitializeComponent();
manualReset = new System.Threading.ManualResetEvent(false);
backgroundWorkerA = new BackgroundWorker();
backgroundWorkerA.WorkerSupportsCancellation = true;
backgroundWorkerA.DoWork += BackgroundWorkerA_DoWork;
backgroundWorkerB = new BackgroundWorker();
backgroundWorkerB.WorkerSupportsCancellation = true;
backgroundWorkerB.DoWork += BackgroundWorkerB_DoWork;
this.HandleCreated += UserControl1_HandleCreated;
}
private void UserControl1_HandleCreated(object sender, EventArgs e)
{
backgroundWorkerA.RunWorkerAsync(_shardList);
backgroundWorkerB.RunWorkerAsync(_shardList);
manualReset.Set();
}
private void BackgroundWorkerB_DoWork(object sender, DoWorkEventArgs e)
{
List<string> _shardList = (List<string>)e.Argument;
manualReset.WaitOne();
int _i = 0;
while(!this.backgroundWorkerB.CancellationPending)
{
_shardList.Add("b" + _i++.ToString());
System.Diagnostics.Debug.WriteLine("b is running");
}
thread2.Invoke(new MethodInvoker(delegate { thread2.Text = string.Join(System.Environment.NewLine, _shardList.ToArray()); }));
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorkerA.CancelAsync();
backgroundWorkerB.CancelAsync();
}
private void BackgroundWorkerA_DoWork(object sender, DoWorkEventArgs e)
{
List<string> _shardList = (List<string>)e.Argument;
manualReset.WaitOne();
int _i = 0;
while (!this.backgroundWorkerA.CancellationPending)
{
_shardList.Add("a" + _i++.ToString());
System.Diagnostics.Debug.WriteLine("a is running");
}
thread1.Invoke(new MethodInvoker(delegate { thread1.Text = string.Join(System.Environment.NewLine, _shardList.ToArray()); }));
}
There are multiple things that make concurrent writes to a List<T> unsafe.
First let's have a look at the code of the Add method:
public void Add(T item) {
if (_size == _items.Length) EnsureCapacity(_size + 1);
_items[_size++] = item;
_version++;
}
The first issue is EnsureCapacity. If the list's inner array isn't big enough to receive the new element, it will create a new, bigger array, and copy the elements from the old one to the new one. If a thread writes in the old list after the copy but before the swap, the element will be lost
The second issue is the non-atomic increment of size. If two threads try to write at the same time, they may write at the same index in the array, thus losing one item
Those race conditions are not very likely, but they'll eventually happen if you keep writing in the same list from multiple threads.
When you modify a list, it has to modify the backing array. If one operation is making a change to the backing array at the same time as another, this can put the list into a broken state. You won't see this often unless you're doing very high frequency concurrent operations, but it's a lot better to use a concurrent collection then to discover the issue in production a few weeks or months later.
The following code just executes 1000000 writes in a row simultaneously on each core. On a multi-core machine, this will almost certainly throw an exception because the underlying array gets modified when another concurrent call is not expecting it.
static void Main(string[] args)
{
var list = new List<string>();
void mutateList()
{
for (var i = 0; i < 1000000; i++)
{
list.Add("foo");
}
}
for (var i = 0; i < Environment.ProcessorCount; i++)
{
new Thread(mutateList).Start();
}
Thread.Sleep(-1);
}

System.Timers.Timer throwing an Exception

I am implementing a code using List<>. Each list has an Class Type item. One of the members of this class is a System.Timer.Timer variable called "TimeOut". The TimeOut.Interval value is 10 and TimeOut.Elapsed Event should be triggered every TimeOut.Interval (which is 10).
The Event is to delete that item from the list. The Event is overloaded such that
TimeOut.Elapsed += (sender, e) => DeleteEntry(sender, e, i)
where i is the index of the item in the list.
For the Event method,
public void DeleteEntry(object sender, System.Timers.ElapsedEventArgs e, int i)
{
//Delete Item from List
listTable.RemoveAt(i);
}
My problem is if two items started their timer together and decided to call the EventHandler after the same specified interval, the one added to the list first is deleted, and then when the second one is called immediately., it throws an error telling me that the index is out of bounds. This happens because one of the items is deleted, the lists shifted its index up and and the "i" sent to the DeleteEntry Method is the old one which is no longer existent.
In other cases when I have more than two items in the list, it deletes the wrong one since the method uses a wrong index.
Using Arrays is not an option for me. Too much work to de-fragment the array every deletion of an element.
How can I solve this? Do I need to do something with the ThreadPool, setting a flag or something like that? Can SynchronizingObject property help in anyway?
Thank you.
Solution:
From what your saying it seems that your problem is the list shifting and you don't know at what point the item is. If that is the case you will want to access the Count property of the list which tells you the amount of items in the list. Be careful working with it as it is does not account for the indexing of 0.
Solution:
From what your saying it seems that your problem is the list shifting and you don't know at what point the item is. If that is the case you will want to access the Count property of the list which tells you the amount of items in the list. Be careful working with it as it is does not account for the indexing of 0.
Edit:
Example:
private static List<int> Numbers = new List<int>();
private static readonly object NumbersLock = new object();
static void Main(string[] args)
{
Thread X = new Thread(() => {
AddNumbers();
});
Thread Y = new Thread(() => {
AddNumbers();
});
X.Start();
Y.Start();
}
private static void AddNumbers() {
Random r = new Random(DateTime.UtcNow.Millisecond);
while (true) {
lock (NumbersLock) {
Numbers.Add(r.Next(0, 100));
}
}
}

Using a BlockingCollection to queue Tasks

I am trying to create a way to queue up Tasks to run, so I have tried to implement it using a BlockingCollection. The problem I find is whenever I try to add the Task, the Task executes. Sample code as below:
private void button1_Click(object sender, EventArgs e)
{
textBox2.Clear();
for (int i = 0; i < 10; i++)
_processCollection.Add(BigTask(i));
}
static BlockingCollection<Task> _processCollection = new BlockingCollection<Task>();
Thread ConsumerThread = new Thread(LaunchConsumer);
private static async void LaunchConsumer()
{
while (true)
{
var processTask = _processCollection.Take();
await Task.Run(() => processTask);
}
}
async Task BigTask(int i)
{
await Task.Delay(5000);
textBox2.AppendText($"Text{i}\n");
}
What seems to happen in debug is all the tasks seem to run as they are added into the blocking collection. I tried switching the blocking collection to use Action, but that just leads to nothing happening. As below (only changes shown):
private void button1_Click(object sender, EventArgs e)
{
textBox2.Clear();
for (int i = 0; i < 10; i++)
{
int iC = i;
_processCollection.Add(async () => await BigTask(iC));
}
}
static BlockingCollection<Action> _processCollection = new BlockingCollection<Action>();
Thread ConsumerThread = new Thread(LaunchConsumer);
private static async void LaunchConsumer()
{
while (true)
{
var processTask = _processCollection.Take();
await Task.Run(processTask);
}
}
I feel like I have made some small error somewhere, because it feels like this should work. I have tried to find someone doing something similar but have had no luck, which makes me think maybe my concept is flawed so feel free to suggest an alternative.
_processCollection.Add(BigTask(i)); doesn't work because this calls BigTask(i) immediately, and when that is called, the work starts.
You were on the right track by wrapping this in a separate BigTask launcher, but by using Action, you don't provide your LaunchConsumer with any means to track the progress. await Task.Run(processTask) will continue pretty much immediately with the next task. You need to use Func<Task> to avoid that.
The reason you don't see any results is likely unrelated. Now that you manage to launch the task from your newly created thread, the call to textBox2.AppendText is no longer done from the UI thread. That's not supported. Only the UI thread can access UI objects. You can use textBox2.Invoke to pass an action back to the UI thread, and that action can then call AppendText.
Tested working code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ConsumerThread.Start();
}
private void button1_Click(object sender, EventArgs e)
{
textBox2.Clear();
foreach (var i in Enumerable.Range(0, 10))
_processCollection.Add(() => BigTask(i));
}
static BlockingCollection<Func<Task>> _processCollection = new BlockingCollection<Func<Task>>();
Thread ConsumerThread = new Thread(LaunchConsumer);
private static async void LaunchConsumer()
{
while (true)
{
var processTask = _processCollection.Take();
await Task.Run(processTask);
}
}
async Task BigTask(int i)
{
await Task.Delay(5000);
textBox2.Invoke(new Action(() => textBox2.AppendText($"Text{i}\n")));
}
}
That said, BlockingCollection is not really the best collection type to use here. It dedicates one thread to pretty much nothing but waiting. Also, Task.Run when you're already in a background thread can admittedly sometimes be useful, but doesn't add anything here. What to do instead depends on your needs. Whether all tasks are known beforehand makes a difference. Whether you may want multiple consumers makes a difference. Other things I haven't thought of may also make a difference.

Start second method after first method is finished with thread functionality c#

I have a method which is rebuilding the product catalog of a webshop. This is neccessary after I change some product information. After the rebuilding method I would like to start a second method to generate full text index of the webshop. I can watch the status of the first method (RebuildCatalog). If the status is "RebuildFinished" then I would like to start the second method (GenerateFullTextIndex). I would like to use Threads functionality. Does someone can create an example of how to implementate this scenario?
I would like to use Threads functionality.
It really doesn't sound like you do. Starting one method after another finishes is as simple as:
var status = RebuildCatalog();
if (status == Status.RebuildFinished)
{
GenerateFullTextIndex();
}
No threading required. If you really think you need multiple threads, you should explain why you think they'll help. At what point do you need to perform multiple tasks concurrently?
Well, if you want to use a multiple threads and oranize your calls in chain so they are executed on another thread, but in sequence, and you are using .NET Framework 4.0>, you can use a Task Parallelism, like for example using Task::ContinueWith method.
Example (preudocode from MSDN):
Task<byte[]> getData = new Task<byte[]>(() => GetFileData());
Task<double[]> analyzeData = getData.ContinueWith(x => Analyze(x.Result));
Task<string> reportData = analyzeData.ContinueWith(y => Summarize(y.Result));
getData.Start();
//or...
Task<string> reportData2 = Task.Factory.StartNew(() => GetFileData())
.ContinueWith((x) => Analyze(x.Result))
.ContinueWith((y) => Summarize(y.Result));
Using events would seem to be simpler than watching the status.
In your rebuild catalog code fire a "finished" event on completion:
public event EventHandler<EventArgs> RebuildFinished;
private void Rebuild(...)
{
// Rebuild the catalog
this.RebuildFinished(this, new EventArgs(...));
}
Then handle it:
this.catalog.RebuildFinished += this.RebuildFinished;
private void RebuildFinished(object sender, EventArgs e)
{
// Rebuild the index
}
Now both of these can (and probably should) be using threads to ensure that the UI of your application stays responsive:
this.catalogThread = new Thread(new ThreadStart(this.catalog.Rebuild));
As I can assume from your question your rebuilding method probably takes up considerable time and that is why you want to run in a separate thread. Therefore I would suggest implementing Event based async pattern. When your rebuilding (async) method finishes it will throw finished event with AsyncCompletedEventArgs (which you can subclass to pass your result status) and from there you will start your second method.
BackgroundWorker bw1 = new BackgroundWorker();//To rebuild catalog.
BackgroundWorker bw2 = new BackgroundWorker();//To generate text.
public Form1()
{
InitializeComponent();
bw1.DoWork += bw1_DoWork;
bw1.RunWorkerCompleted += bw1_RunWorkerCompleted;
bw2.DoWork += bw2_DoWork;
bw2.RunWorkerCompleted += bw2_RunWorkerCompleted;
bw1.RunWorkerAsync();//Start new thread. - Rebuild catalog.
}
void bw1_DoWork(object sender, DoWorkEventArgs e)
{
//Rebuild catalog.
}
void bw1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bw2.RunWorkerAsync();//Generate text.
}
void bw2_DoWork(object sender, DoWorkEventArgs e)
{
//Generate text.
}
void bw2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Whatever...
}

Categories