I have a queue of users(string of emails) a in c# and I want to send the user his location in this queue.
something like ;
Queue q = new Queue(32);
q.Enqueue(Session["email"].ToString());
queue.IndexOf(email);
Any ideas?
thanks
Maybe a List or an Array would be better for such actions but you could try this:
queue.ToArray().ToList().IndexOf(email);
You can use extension method, something like:
public static int IndexOf<T>(this IEnumerable<T> collection, T searchItem)
{
int index = 0;
foreach (var item in collection)
{
if (EqualityComparer<T>.Default.Equals(item, searchItem))
{
return index;
}
index++;
}
return -1;
}
Queue is not the proper type to use IndexOf, look for List
Unfortunately, you cannot straightly use the plain old .NET Queue object. Queue is made for "blind" first-in-first-out logic, so that you cannot perform anything else but that.
If you really need to implement a queue in which you can find elements and retrieve their position (a very useful thing) try to wrap everything in a class that exposes the following methods:
public class CustomQueue<T> {
private LinkedList<T> fifoList = new LinkedList<T>();
public Enqueue(T newItem) {
//add newItem at the head of fifoList
}
public T Dequeue() {
//return and remove the item that is located at the tail of the queue
}
public int indexOf(T searchFor) {
int ret = 0;
for (T item: fifoList) {
if (item.equals(searchFor)) return ret;
ret++;
}
}
}
For better performance (queue and dequeue O(1) while indexOf O(n)) you should use a double-linked list
if you want to let the user now how many elements are behins his element, simply return the current queue .Count property, after inserting his elements. Whenever you push an elemtn, the count is increased. If an element is popped, the count is decreased.
Use the Queue's ToArray() method to get an array in the order of the queue, then find the object you are searching for. There's a good chance you don't need to use a traditional queue for whatever task you are performing though.
Something like:
Queue q = new Queue();
q.Enqueue("apple");
q.Enqueue("banana");
q.Enqueue("orange");
// get banana index:
return Array.IndexOf(q.ToArray(), "banana");
Spanish Inquisition
Inspired by Monty Python sketch you could swipe through the entire queue of suspects and dequeue and enqueue each item once. And while you are at it you can use a lambda function to kind of keep the dequeuing within the enquing operation
//The queue
var inquisition = new Queue<string>();
//Suspects
inquisition.Enqueue("SUSPECT_A");
inquisition.Enqueue("SUSPECT_B");
inquisition.Enqueue("SUSPECT_C");
//Interrogation lambda function noting particular suspect before returned
Func<string, string> interrogate = (suspect) => {
Console.WriteLine(suspect + (suspect.Equals("SUSPECT_B") ? " <---" : ""));
return suspect;
};
//Processing each suspect in the list
for(var i=0;i<inquisition.Count;i++){
inquisition.Enqueue(interrogate(inquisition.Dequeue()));
}
The result is a list of suspects where dubious ones are marked with an arrow
SUSPECT_A
SUSPECT_B <---
SUSPECT_C
I know this is an older thread, but was relevant to me. In my case the Queue object was perfect for the job it was intended to do, but I had a separate process that reports a status of the objects in queue and I wanted to report the queue position for each queued item. Here was my solution and this illustrates how converting a queue to a list can be helpful. Once converted to a list, you can perform Linq queries on it as well. In this case, I needed to find an export object by its status property:
Dim ExpQueueList As List(Of Export) = ExportQueue.ToList()
For Idx As Integer = 0 To ExportStatuses.Count - 1
Dim Status As ExportStatus = ExportStatuses(Idx)
'Find the export that this status belongs to in the queued export list
Dim ExpObj As Object = (From E As Export In ExpQueueList Where E.Status Is Status Select E).FirstOrDefault()
'If the export was found in the queue list, set the status text to indicate the position in the queue
If ExpObj IsNot Nothing Then
Status.StatusText = "In Queue to run - Queue Position: " & ExpQueueList.IndexOf(ExpObj)
End If
ExpObj = Nothing
Status = Nothing
Next
Since you're enqueing the user, he will always be the last person in the list, which means it will be equivalent to queue.Count.
Related
Let's say i have a update function like that:
for (int i = 0; i < players.Count; i++)
{
Debug.Log(players[i].name);
}
This list is being used in Update() so if i remove any of list items from another script/function it will just throw a error because list size is changed while loop is going on. How do i fix this?
This bug bug pops up everywhere in programming where you are working with some collection that might modify the collection you are working with.
In my experience there are two options:
Take a copy of the collection and work with the copy, if it is okay to show out of date information.
Handle any errors that occur from the collection being modified and restart your logic using the latest collection.
Option 1: Work with a copy:
Before accessing the collection, take a copy of what is in memory. For example, use.ToList() or .ToArray()
var playersCopy = players.ToList();
for (int i = 0; i < playersCopy .Count; i++)
{
Debug.Log(playersCopy [i].name);
}
Using this approach you have a copy in memory that cannot be modified, even thought that copy can possible be stale or out of date.
2). If using a stale copy is not acceptable, then you need to handle an exceptions that occur from the collection being modified while you are iterating through it.
For example, you can put access to the collection inside of a try catch and retry your logic if the collection was modified.
bool success = false;
while(!success)
{
try {
{
for (int i = 0; i < players.Count; i++)
{
Debug.Log(players[i].name);
}
success=true; // loop completed without error
}
catch { }
}
Note the later is a simplified example and depending on your circumstance you might want to do different actions with the caught error.
Also note, that latter is not recommended if there are side effects For example, Debug.Log might already have printed out a stale player.
This has its own solutions, EG: Save the player names to a list first and then print out the in memory list or again use custom logic (for example, track which players are no longer in the list and print a message saying they left and continue with the rest of the list).
Still the approach is the same, use an in memory copy or detect the changes in real time and handle them.
Fortunately, based on the information you supplied, this won't throw an error.
In a standard scenario, the Update method will be called and complete before the next Update method on the following script is called. The main Unity worker thread isn't being called from anywhere else, so one script wouldn't interrupt an Update method call mid function.
Now, if you had said you were using co-routines, and had yielded during a 'foreach' loop, then in that case, you might have a scenario whereby the enumerator threw an error, because you could have modified the underlying enumerable (players) from somewhere else in this script, or another.
Another way to put it, this is bad:
public class Base : MonoBehaviour
{
List<int> list;
void Start ( )
{
list = new List<int> { 1, 2, 3, 4 };
StartCoroutine ( ForEachTest ( ) );
list.Add ( 5 );
}
IEnumerator ForEachTest ( )
{
foreach ( var item in list )
{
Debug.Log ( $"Item value : {item}" );
yield return null;
}
}
}
Would result in:
InvalidOperationException: Collection was modified; enumeration
operation may not execute.
If you take a look at the code for the enumerator, you can see why an Exception is thrown.
public bool MoveNext()
{
List<T> list = this.list;
if (version == list._version && (uint)index < (uint)list._size)
{
current = list._items[index];
index++;
return true;
}
return MoveNextRare();
}
private bool MoveNextRare()
{
if (version != list._version)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
index = list._size + 1;
current = default(T);
return false;
}
When a List (as suggested by your use of Count, not Length) is modified, the enumerator sees that the collection's version has been modified, which invalidates the enumerator.
Note, that if you don't use an enumerator, and simply use a for loop that is checking the list's Count property, you won't run into this problem.
I have a dictionary that is being used in two threads, one is sending out UDP packets, one is receiving them. Both are keeping a common collection to see count outgoing and returning packets and hopefully keeping them at 0 difference :)
Now I'm iterating through the dictionary to update values and after iteration it errors. I do have a lock object in place, how could I solve this?
First Thread:
lock (retryListLock)
{
// loop through all known devices in the device list to build a counter if the device still lives
foreach(string key in retryList.Keys)
{
retryList[key] += 1;
if (retryList[key] > Retries)
{
DiscoveredDevice device = Devices.Find(d => d.SerialNo == key);
if (device != null)
{
OnDeviceRemoved(device);
Devices.Remove(device);
retryList.Remove(key);
}
}
}
}
Second Thread:
lock (retryListLock)
{
if (retryList.ContainsKey(frame.SerialNo))
retryList[frame.SerialNo] = 0;
else
retryList.Add(frame.SerialNo, 0);
}
I'm only getting the error after the first thread adds +1 to the value of that item, in the second iteration it errors out:
the collection has changed. enumeration operation may not execute (translated from Dutch)
How can I solve this? Obviously the Dictionary is the easiest to use for me in this case.
The problem is that you cannot change the dictionary in an iterator/foreach
foreach(string key in retryList.Keys)
{
retryList[key] += 1; // <-- The error happens here ! Do not alter the Dictionary during an iteration
if (retryList[key] > Retries)
{
DiscoveredDevice device = Devices.Find(d => d.SerialNo == key);
if (device != null)
{
OnDeviceRemoved(device);
Devices.Remove(device);
retryList.Remove(key); // <-- The error could also happen here ! Do not alter the Dictionary during an iteration
}
}
}
I found this question on stackoverflow which might help you
How to iterate through Dictionary and change values?
Here we find a statement from MSDN
The foreach statement is a wrapper around the enumerator, which allows
only reading from the collection, not writing to it.
With thanks to Bongo, taking the keys into a second list for iteration solved it:
List<string> Keys = new List<string>(retryList.Keys);
foreach(string key in Keys)
The error has nothing to do with the locks and multithreading.
Your enumerator (what foreach are using) is invalidated when you modify the very same data structure (the dictionary) on what the enumerator enumerates in the loop.
Solution:
You must first loop say with foreach, and remember practically in a list what you should remove. Then in a separate loop on the remembered keys, remove they from the dictionary.
This might be useful to you. Concurrent Dictionary
It's thread safe
Also change the for each to a reverse for loop
Something like this.
for (int x = max; x>=1; x--)
{
}
How to write a thread-safe list using copy-on-write model in .NET?
Below is my current implementation, but after lots of reading about threading, memory barriers, etc, I know that I need to be cautious when multi-threading without locks is involved. Could someone comment if this is the correct implementation?
class CopyOnWriteList
{
private List<string> list = new List<string>();
private object listLock = new object();
public void Add(string item)
{
lock (listLock)
{
list = new List<string>(list) { item };
}
}
public void Remove(string item)
{
lock (listLock)
{
var tmpList = new List<string>(list);
tmpList.Remove(item);
list = tmpList;
}
}
public bool Contains(string item)
{
return list.Contains(item);
}
public string Get(int index)
{
return list[index];
}
}
EDIT
To be more specific: is above code thread safe, or should I add something more? Also, will all thread eventually see change in list reference? Or maybe I should add volatile keyword on list field or Thread.MemoryBarrier in Contains method between accessing reference and calling method on it?
Here is for example Java implementation, looks like my above code, but is such approach also thread-safe in .NET?
And here is the same question, but also in Java.
Here is another question related to this one.
Implementation is correct because reference assignment is atomic in accordance to Atomicity of variable references. I would add volatile to list.
Your approach looks correct, but I'd recommend using a string[] rather than a List<string> to hold your data. When you're adding an item, you know exactly how many items are going to be in the resulting collection, so you can create a new array of exactly the size required. When removing an item, you can grab a copy of the list reference and search it for your item before making a copy; if it turns out that the item doesn't exist, there's no need to remove it. If it does exist, you can create a new array of the exact required size, and copy to the new array all the items preceding or following the item to be removed.
Another thing you might want to consider would be to use a int[1] as your lock flag, and use a pattern something like:
static string[] withAddedItem(string[] oldList, string dat)
{
string[] result = new string[oldList.Length+1];
Array.Copy(oldList, result, oldList.Length);
return result;
}
int Add(string dat) // Returns index of newly-added item
{
string[] oldList, newList;
if (listLock[0] == 0)
{
oldList = list;
newList = withAddedItem(oldList, dat);
if (System.Threading.Interlocked.CompareExchange(list, newList, oldList) == oldList)
return newList.Length;
}
System.Threading.Interlocked.Increment(listLock[0]);
lock (listLock)
{
do
{
oldList = list;
newList = withAddedItem(oldList, dat);
} while (System.Threading.Interlocked.CompareExchange(list, newList, oldList) != oldList);
}
System.Threading.Interlocked.Decrement(listLock[0]);
return newList.Length;
}
If there is no write contention, the CompareExchange will succeed without having to acquire a lock. If there is write contention, writes will be serialized by the lock. Note that the lock here is neither necessary nor sufficient to ensure correctness. Its purpose is to avoid thrashing in the event of write contention. It is possible that thread #1 might get past its first "if" test, and get task task-switched out while many other threads simultaneously try to write the list and start using the lock. If that occurs, thread #1 might then "surprise" the thread in the lock by performing its own CompareExchange. Such an action would result in the lock-holding thread having to waste time making a new array, but that situation should arise rarely enough that the occasional cost of an extra array copy shouldn't matter.
Yes, it is thread-safe:
Collection modifications in Add and Remove are done on separate collections, so it avoids concurrent access to the same collection from Add and Remove or from Add/Remove and Contains/Get.
Assignment of the new collection is done inside lock, which is just pair of Monitor.Enter and Monitor.Exit, which both do a full memory barrier as noted here, which means that after the lock all threads should observe the new value of list field.
I wrote a program designed to create a randomish list of numbers from a given starting point. It was a quick a dirty thing but I found an interesting effect when playing with it that I don't quite understand.
void Main()
{
List<int> foo = new List<int>(){1,2,3};
IEnumerable<int> bar = GetNumbers(foo);
for (int i = 1; i < 3; i++)
{
foo = new List<int>(){1,2,3};
var wibble = GetNumbers(foo);
bar = bar.Concat(wibble);
}
Iterate(bar);
Iterate(bar);
}
public void Iterate(IEnumerable<int> numbers)
{
Console.WriteLine("iterating");
foreach(int number in numbers)
{
Console.WriteLine(number);
}
}
public IEnumerable<int> GetNumbers(List<int> input)
{
//This function originally did more but this is a cutdown version for testing.
while (input.Count>0)
{
int returnvalue = input[0];
input.Remove(input[0]);
yield return returnvalue;
}
}
The output of runing this is:
iterating
1
2
3
1
2
3
1
2
3
iterating
That is to say the second time I iterate through bar immediately after it is empty.
I assume this is something to do with the fact that the first time I iterate that it empties the lists that are being used to generate the list and subsequently it is using these same lists that are now empty to iterate.
My confusion is on why this is happening? Why do my IEnumerables not start from their default state each time I enumerate over them? Can somebody explain what exactly I'm doing here?
And to be clear I know that I can solve this problem by adding a .ToList() to my call to GetNumbers() which forces immediate evaluation and storage of the results.
Your iterator does start from its initial state. However, it modifies the list it's reading from, and once the list is cleared, your iterator doesn't have anything left to do. Basically, consider
var list = new List<int> { 1, 2, 3 };
var enumerable = list.Where(i => i != 2);
foreach (var item in enumerable)
Console.WriteLine(item);
list.Clear();
foreach (var item in enumerable)
Console.WriteLine(item);
enumerable doesn't get changed by list.Clear();, but the results it gives do.
Your observation can be reproduced with this shorter version of the main method:
void Main()
{
List<int> foo = new List<int>(){1,2,3};
IEnumerable<int> bar = GetNumbers(foo);
Console.WriteLine(foo.Count); // prints 3
Iterate(bar);
Console.WriteLine(foo.Count); // prints 0
Iterate(bar);
}
What happens is the following:
When you call GetNumbers it isn't really being executed. It will only be executed when you iterate over the result. You can verify this by putting Console.WriteLine(foo.Count); between the call to GetNumbers and Iterate.
On the first call to Iterate, GetNumbers is executed and empties foo.
On the second call to Iterate, GetNumbers is executed again, but now foo is empty, so there is nothing left to return.
Well, the lazy evaluation is what hit you. You see, when you create a yield return-style method, it's not executed immediately upon call. It'll be however executed as soon as you iterate over the sequence.
So, this means that the list won't be cleared during GetNumbers, but only during Iterate. In fact, the whole body of the function GetNumbers will be executed only during Iterate.
You problem is that you made your IEnumersbles depend not only on inner state, but on outer state as well. That outer state is the content of foo lists.
So, the all the lists are filled until you Iterate the first time. (The IEnumerable created by GetNumbers holds a reference to them, so the fact that you overwrite foo doesn't matter.) All the three are emptied during the first Iterate. Next, the next iteration starts with the same inner state, but changed outer state, giving different result.
I'd like to notice, that mutation and depending on outer state is generally frowned upon in functional programming style. The LINQ is actually a step toward functional programming, so it's a good idea to follow the FP's rules. So you could do better with just not removing the items from input in GetNumbers.
I'm trying to make my application thread safe. I hold my hands up and admit I'm new to threading so not sure what way to proceed.
To give a simplified version, my application contains a list.
Most of the application accesses this list and doesn't change it but
may enumerate through it. All this happens on the UI thread.
Thread
one will periodically look for items to be Added and Removed from the
list.
Thread two will enumerate the list and update the items with
extra information. This has to run at the same time as thread one as
can take anything from seconds to hours.
The first question is does anyone have a recommend stragy for this.
Secondly I was trying to make seperate copies of the list that the main application will use, periodically getting a new copy when something is updated/added or removed, but this doesn't seem to be working.
I have my list and a copy......
public class MDGlobalObjects
{
public List<T> mainList= new List<T>();
public List<T> copyList
{
get
{
return new List<T>(mainList);
}
}
}
If I get copyList, modify it, save mainlist, restart my application, load mainlist and look again at copylist then the changes are present. I presume I've done something wrong as copylist seems to still refer to mainlist.
I'm not sure if it makes a difference but everything is accessed through a static instance of the class.
public static MDGlobalObjects CacheObjects = new MDGlobalObjects();
This is the gist using a ConcurrentDictionary:
public class Element
{
public string Key { get; set; }
public string Property { get; set; }
public Element CreateCopy()
{
return new Element
{
Key = this.Key,
Property = this.Property,
};
}
}
var d = new ConcurrentDictionary<string, Element>();
// thread 1
// prune
foreach ( var kv in d )
{
if ( kv.Value.Property == "ToBeRemoved" )
{
Element dummy = null;
d.TryRemove( kv.Key, out dummy );
}
}
// thread 1
// add
Element toBeAdded = new Element();
// set basic properties here
d.TryAdd( toBeAdded.Key, toBeAdded );
// thread 2
// populate element
Element unPopulated = null;
if ( d.TryGetValue( "ToBePopulated", out unPopulated ) )
{
Element nowPopulated = unPopulated.CreateCopy();
nowPopulated.Property = "Populated";
// either
d.TryUpdate( unPopulated.Key, nowPopulated, unPopulated );
// or
d.AddOrUpdate( unPopulated.Key, nowPopulated, ( key, value ) => nowPopulated );
}
// read threads
// enumerate
foreach ( Element element in d.Values )
{
// do something with each element
}
// read threads
// try to get specific element
Element specific = null;
if ( d.TryGetValue( "SpecificKey", out specific ) )
{
// do something with specific element
}
In thread 2, if you can set properties so that the whole object is consistent after each atomic write, then you can skip making a copy and just populate the properties with the object in place in the collection.
There are a few race conditions in this code, but they should be benign in that readers always have a consistent view of the collection.
actly copylist is just a shallow copy of the mainList. the list is new but the refrences of the objects contained in the list are still the same. to achieve what you are trying to you have to make a deep copy of the list
something like this
public static IEnumerable<T> Clone<T>(this IEnumerable<T> collection) where T : ICloneable
{
return collection.Select(item => (T)item.Clone());
}
and use it like
return mainList.Clone();
looking at your ques again.. i would like to suggest an overall change of approach.
you should use ConcurrentDictionary() as you are using .Net 4.0. in that you wont hav eto use locks as a concurrent collection always maintains a valid state.
so your code will look something like this.
Thread 1s code --- <br>
var object = download_the_object();
dic.TryAdd("SomeUniqueKeyOfTheObject",object);
//try add will return false so implement some sort of retry mechanism
Thread 2s code
foreach(var item in Dictionary)
{
var object item.Value;
var extraInfo = downloadExtraInfoforObject(object);
//update object by using Update
dictionary.TryUpdate(object.uniqueKey,"somenewobjectWithExtraInfoAdded",object);
}