I am using yield return to process some data, with a non-deterministic set of iterations. I want to start processing, but break from the loop once a condition has been hit (e.g. byte size), pass the enumerator to a new thread that will continue to process, and then return the results processed so far.
In effect I have a foreach loop which I will likely break out of before the end. How can I pass the IEnumerable to a new thread and 'continue' from where I left off rather than the beginning?
public static IEnumerable<String> Process()
{
// static values added for simplicity, but will be a variable number of returns
yield return "1";
yield return "2";
yield return "3";
yield return "4";
yield return "5";
yield return "6";
}
List<String> main()
{
List<String> retVal = new List<String>();
IEnumerable<String> strList = Process();
foreach(String strItem in strList)
{
retVal.Add(strItem);
Console.WriteLine(strItem);
// Time to send something back and continue in a new thread
if (strItem.Equals("3"))
{
break;
}
}
new Thread(() => ThreadFunc(strList)).Start();
return retVal;
}
public static void ThreadFunc(IEnumerable<String> strList)
{
List<String> retVal = new List<String>();
foreach(String strItem in strList)
{
retVal.Add(strItem);
Console.WriteLine(strItem);
}
// Send the rest of the data
}
Desired output: 1 2 3 4 5 6
Actual output: 1 2 3 1 2 3 4 5 6
Thank You.
Look at what the IEnumerable<T>
interface actually does.
IEnumerable<T>
is completely stateless; it just exposes a GetEnumerator()
method, which hands back stateful enumerators that keep track of where they're up to.
You need to pass the same enumerator instance between your two loops. foreach
can only operate on IEnumerable<T>
(or similar), so you'll need to replace them with while
loops that use IEnumerator<T>
directly.
Make sure to dispose the IEnumerator
in all codepaths (otherwise, finally
or using
blocks won't run).