Reputation: 31
I have a singleton IEnumerable that generates a sequence of numbers. The sequence is interable (basically indefinitely) and I generate the next number in the sequence only when needed.
public class Generator:IEnumerable<long> {
private Generator() { }
private static volatile Generator instance=new Generator();
private static readonly object syncRoot=new object();
public static Generator Instance { get { return instance; } }
private static List<long> numsList=new List<long>();
private void GenerateNextNumber() {
long number;
//Code to generate next number
numsList.Add(number);
}
private long GenerateToNthNumber(int n) {
lock(syncRoot) {
while(numsList.Count<n)
GenerateNextNumber();
}
return numsList[n-1];
}
public static long GetNthNumber(int n) {
return Instance.GenerateToNthNumber(n);
}
private class GeneratorEnumerator:IEnumerator<long> {
private int index=0;
public long Current { get { return GetNthNumber(index); } }
public void Dispose() { }
object System.Collections.IEnumerator.Current { get { return GetNthNumber(index); } }
public bool MoveNext() {
index++;
return true;
}
public void Reset() {
index=0;
}
}
public IEnumerator<long> GetEnumerator() {
return new GeneratorEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
This code works enumerating through and summing the numbers in concurrent threads. Is there a way to prevent having to lock every time GenerateToNthNumber is called? I tried this code:
private long GenerateToNthNumber(int n) {
if(numsList.Count<n) {
lock(syncRoot) {
while(numsList.Count<n)
GenerateNextNumber();
}
}
return numsList[n-1];
}
But when testing enumerating through and summing the numbers in multiple concurrent threads, not all the results end up with the same sum. My objective is to have non-blocking reads if the number being asked for is already generated, if that is even possible. Is there a better way to do this?
Upvotes: 3
Views: 316
Reputation: 81159
The way List
is implemented, it cannot be safely read in one thread while it is being written in another. I would suggest that instead you use nested known-size arrays which, once allocated, are never abandoned (e.g. once an array is allocated that will hold theList[15691]
, the item will never be held by any other array). Such things may easily be used to implement an add-only list which requires locking when adding items, but is inherently thread-safe for reading without locking.
Upvotes: 1
Reputation: 756
Have you thought about using a thread safe collection?
http://msdn.microsoft.com/en-us/library/dd997305.aspx
Upvotes: 0