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));
}
}
}
Related
I'm writing a C# library that needs to treat a List at high speed via multiple Timers.
I ran into very erratic error, where I try to remove an element that I know for sure is contained into the List but the program returns the following error :
System.IndexOutOfRangeException : 'index was outside the bounds of the array.'
I've made a simple example to reproduce this behaviour. Because of that issue's randomness, I've pushed hard on List operations so it throws the error right away. So this example is necessary "weird".
I've made a public repo on here : Issue Example Repo
Basically, here's what I'm dealing with:
list = new List<DummyElement>();
for (int i = 0; i < 1000; i++)
{
Timer addTimer = new Timer(0.01f);
addTimer.Start();
addTimer.Elapsed += AddItem;
Timer removeTimer = new Timer(0.01f);
removeTimer.Start();
removeTimer.Elapsed += RemoveItem;
}
void AddItem(object source, ElapsedEventArgs e)
{
list.Add(new DummyElement());
}
void RemoveItem(object source, ElapsedEventArgs e)
{
int listCount = list.Count;
if (listCount > 0) // This condition is successfully passed, so there is at least one element on the list
{
list.RemoveAt(0); // This line throw an IndexOutOfRangeException error
}
}
I believe it is a thread related issue, as if the list count was changing AFTER the condition was successfully passed.
I know nothing about thread, how can I deal with this issue?
In the For loop that goes upto 1000 - you are creating about 1000 Timers that add an item into list and 1000 timers that remove first item.
Since you haven't used any synchronization here's what happens:- Say there is 1 item in List and 2 RemoveItems are executing. both see listCount > 0 as True then one of them goes ahead and removes the Item at 0th Index while the other gets an Exception cause there is no item to remove now.
Now I cant suggest a solution to this by just looking at the code. I also need to understand the intent.
This is a Text Book Producer Consumer problem so the Text book advice here is using Lock construct:
Assume you have a class member like:
private object _lockMe = new object();
void RemoveItem(object source, ElapsedEventArgs e)
{
lock(_lockMe)
{
int listCount = list.Count;
if (listCount > 0) // This condition is successfully passed, so there is at least one element on the list
{
list.RemoveAt(0); // This line throw an IndexOutOfRangeException error
}
}
}
So I have a list with 900+ entries in C#. For every entry in the list a method has to be executed, though these must go all at the same time. First I thought of doing this:
public void InitializeThread()
{
Thread myThread = new Thread(run());
myThread.Start();
}
public void run()
{
foreach(Object o in ObjectList)
{
othermethod();
}
}
Now the problem here is that this will execute 1 method at a time for each entry in the list. But I want every single one of them to be running at the same time.
Then I tried making a seperate thread for each entry like this:
public void InitializeThread()
{
foreach(Object o in ObjectList)
{
Thread myThread = new Thread(run());
myThread.Start();
}
}
public void run()
{
while(//thread is allowed to run)
{
// do stuff
}
}
But this seems to give me system.outofmemory exceptions (not a suprise since the list has almost a 1000 entries.
Is there a way to succesfully run all those methods at the same time? Either using multiple threads or only one?
What I'm ultimately trying to achieve is this: I have a GMap, and want to have a few markers on it. These markers represent trains. The marker pops up on the GMap at a certain point in time, and dissappears when it reaches it's destination. All the trains move about at the same time on the map.
If I need to post more of the code I tried please let me know.
Thanks in advance!
What you're looking for is Parallel.ForEach:
Executes a foreach operation on an IEnumerable in which iterations may
run in parallel.
And you use it like this:
Parallel.ForEach(ObjectList, (obj) =>
{
// Do parallel work here on each object
});
Heres a quick question. I have an ObservableCollection<IItem> where IItem has a property called Id. Throughout the lifetime of an application items are added, removed and then re-added once again to this collection.
What I need is to track when items with certain id's are present in this collection. When all required dependencies are present, I need to do some initialization, if at least one of the required items is removed, then I need to do a cleanup. If that item is then re-added once again, then I need to do initialization again.
Any suggestions what RX operators to use to build such kind of a query?
Keeping track of the state of the collection will probably be somewhat tedious. Unless your collection is very big you can instead examine the collection on each change to determine if your criteria for initialization is fulfilled. Then you can use DistinctUntilChanged to get an observable that will fire when you need to perform initialization and cleanup
Here is an example:
var collection = new ObservableCollection<Int32>();
var observable = Observable
.FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
handler => collection.CollectionChanged += handler,
handler => collection.CollectionChanged -= handler
);
You then need a predicate that determines if initialization is required (the collection "is ready"). This predicate can get expensive if your collection is big because it will be called on each change to the collection, but my assumption is that this is not a problem.
Boolean IsReady(IEnumerable<Int32> items, IReadOnlyList<Int32> itemsRequiredToBeReady) {
return items.Intersect(itemsRequiredToBeReady).Count() == itemsRequiredToBeReady.Count;
}
Then you can use DistinctUntilChanged to get notifications when the IsReady predicate changes from true to false and vice versa:
var isReadyObservable = observable
.Select(ep => IsReady((ObservableCollection<Int32>) ep.Sender, ItemsRequiredToBeReady))
.DistinctUntilChanged();
To initialize and cleanup you need two subscriptions:
isReadyObservable.Where(isReady => isReady).Subscribe(_ => Initialize());
isReadyObservable.Where(isReady => !isReady).Subscribe(_ => Cleanup());
ObservableCollection is not quite observable as it turns out, so first you must consider what is the strategy you are going to employ in this case. If it is just added and removed items than this code should suffice.
internal class Program
{
private static ObservableCollection<IItem> oc = new ObservableCollection<IItem>();
private static readonly long[] crossCheck = {1,2,3};
private static void Main(string[] args)
{
oc.CollectionChanged += oc_CollectionChanged;
oc.Add(new IItem {Id=1,Amount = 100});
oc.Add(new IItem {Id=2,Amount = 200});
oc.Add(new IItem {Id=3,Amount = 300});
oc.RemoveAt(1);
}
private static void oc_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Console.WriteLine("{0} {1}", e.Action, oc.Sum(s1 => s1.Amount));
if (crossCheck.SequenceEqual(oc.Select(s1 => s1.Id).Intersect(crossCheck)))
Console.WriteLine("I have all elements I wanted!");
if (e.OldItems != null && e.Action.Equals(NotifyCollectionChangedAction.Remove) &&
e.OldItems.Cast<IItem>().Any(a1 => a1.Id.Equals(2))) Console.WriteLine("I've lost item two");
}
}
internal class IItem
{
public long Id { get; set; }
public int Amount { get; set; }
}
Produces:
Add 100
Add 300
Add 600
I have all elements I wanted!
Remove 400
I've lost item two
Press any key to continue . . .
Of course in your event handler you can process other conditions as needed, for example you probably want to fire some of those data dependent events just once, etc.
I have an WinRT application that fires notifications everytime it recieves data from a device. I also have a UI control that is databound to an observable collection which I wish to add the new data to
While I have made it capable of updating the observable collection, it causes the UI to become very laggy, as the amount of data generated it fast. It would therefore be better to batch the update, maybe every few hundred milliseconds.
Below shows a snippet of the code. First I create the periodic timer
TimerElapsedHandler f = new TimerElapsedHandler(batchUpdate);
CreatePeriodicTimer(f, new TimeSpan(0, 0, 3));
Below is my event handler for when new data comes in, along with the temporary list that stores the information
List<FinancialStuff> lst = new List<FinancialStuff>();
async void myData_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
var data = new byte[args.CharacteristicValue.Length];
DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(data);
lst.Add(new FinancialStuff() { Time = "DateTime.UtcNow.ToString("mm:ss.ffffff")", Amount = data[0] });
}
Then my batch update, which is called peroidically
private void batchUpdate(ThreadPoolTimer source)
{
AddItem<FinancialStuff>(financialStuffList, lst);
}
Then finally, for testing I want to clear the observable collection and items.
public async void AddItem<T>(ObservableCollection<T> oc, List<T> items)
{
lock (items)
{
if (Dispatcher.HasThreadAccess)
{
foreach (T item in items)
oc.Add(item);
}
else
{
Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
oc.Clear();
for (int i = 0; i < items.Count; i++)
{
items.Count());
oc.Add(items[i]);
}
lst.Clear();
});
}
}
}
While this seems to work, after a few updates the UI locks up and it updates very slowly/if not at all. For testing, it's only getting a few hundred items in the list by the time the timer is fired.
Can anybody enlighten me as to why as to why this is happening - I'm presuming my design is very poor.
Thanks
You're not locking your list in the event handler
// "lst" is never locked in your event handler
List<FinancialStuff> lst = new List<FinancialStuff>();
lst.Add(new FinancialStuff() { Time = "DateTime.UtcNow.ToString("mm:ss.ffffff")", Amount = data[0] });
Passing "lst" above to your async method
AddItem<FinancialStuff>(financialStuffList, lst);
You're locking "items" below, which is really "lst" above. However, you're adding to the list while your processing it. I assume the event handler has a higher priority so your processing is slower than your add. This can lead to "i < items.Count" being true forever.
public async void AddItem<T>(ObservableCollection<T> oc, List<T> items)
{
// "lst" reference is locked here, but it wasn't locked in the event handler
lock (items)
{
if (Dispatcher.HasThreadAccess)
{
foreach (T item in items)
oc.Add(item);
}
else
{
Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
oc.Clear();
// This may never exit the for loop
for (int i = 0; i < items.Count; i++)
{
items.Count());
oc.Add(items[i]);
}
lst.Clear();
});
}
}
}
EDIT:
Do you need to view every piece of data? There is going to be some overhead when using a lock. If you're getting data quicker than the speed of how fast you can render it, you'll eventually be backed up and/or have a very large collection to render, which might also cause some problems. I suggest you do some filtering to only draw the last x number of items (say 100). Also, I'm not sure why you need the if (Dispatcher.HasThreadAccess) condition either.
Try the following:
public async void AddItem<T>(ObservableCollection<T> oc, List<T> items)
{
// "lst" reference is locked here, but it wasn't locked in the event handler
lock (items)
{
// Change this to what you want
const int maxSize = 100;
// Make sure it doesn't index out of bounds
int startIndex = Math.Max(0, items.Count - maxSize);
int length = items.Count - startIndex;
List<T> itemsToRender = items.GetRange(startIndex, length);
// You can clear it here in your background thread. The references to the objects
// are now in the itemsToRender list.
lst.Clear();
// Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
// Please verify this is the correct syntax
Dispatcher.Run(() =>
{
// At second look, this might need to be locked too
// EDIT: This probably will just add overhead now that it's not running async.
// You can probably remove this lock
lock(oc)
{
oc.Clear();
for (int i = 0; i < itemsToRender.Count; i++)
{
// I didn't notice it before, but why are you checking the count again?
// items.Count());
oc.Add(itemsToRender[i]);
}
}
});
}
}
EDIT2:
Since your AddItem method is already on a background thread, I don't think you need to run the Dispatcher.RunAsync. Instead, I think it might be desirable for it to block so you don't end up with multiple calls to that section of code. Try using Dispatcher.Run instead. I've updated the code example above to show the changes. You shouldn't need the lock on the oc anymore since the lock on the items is good enough. Also, verify the syntax for Dispatcher.Run is correct.
I'll try to keep this as simple as possible. Here's my method, just to start - and I understand the below code is incorrect - this is just what I have at the moment:
public static void GetActorsFromCastList(TmdbMovieCast cast)
{
// use timers here
List<Cast> liCast = cast.cast;
Timer actorTimer = new Timer(1000);
// put the below into a foreach loop to get a new personId each time???
foreach (var i in liCast)
{
actorTimer.Elapsed += new ElapsedEventHandler((sender, e) => RunActorEvent(sender, e, i.id));
actorTimer.Start();
}
}
public static void RunActorEvent(object sender, ElapsedEventArgs e, int personId)
{
// run a single API call here to get a Person (actor)
_actors.Add(_api.GetPersonInfo(personId));
}
As you can see, I created a System.Timer that, as designed above, the idea is to call the RunActorEvent every second and pass in a different PersonId each time. The end goal is to call the RunActorEvent one time each second, but each time pass in a new PersonId. I already created the ElapsedEventHandler such that I added a third parameter PersonId.
That's where I'm at. The dilemma I'm having is this just doesn't look correct. I mean, I have a foreach loop that essentially creates a new ElapsedEventHander through each iteration, and I don't think this should be the design.
QUESTION: How do I create a System.Timer and a corresponding ElapsedEventHandler but pass in a new variable (PersonId) into RunActorEvent (the Event Handler) each time the ElapsedEventHander is called?
You can pass the List<Cast> to your event, Have a class level index on list and increment that index each time in the event something like:
actorTimer.Elapsed += new ElapsedEventHandler((sender, e) => RunActorEvent(sender, e, liCast));
Then in method:
int index = 0; //class level index
public static void RunActorEvent(object sender, ElapsedEventArgs e, List<Cast> list)
{
int personId = list.ElementAt(index++); //or list[index++]
_actors.Add(_api.GetPersonInfo(personId));
}
Just another way of writing it which, in my opinion, is a bit cleaner...
actorTimer.Elapsed += (sender, e) => RunActorEvent(sender, e, personId);
Unrelated to your question, but this line hurts:
List<Cast> liCast = cast.cast;
cast.cast just doesn't make sense at all.