Просто для этого я пытаюсь подражать тому, как генераторы JRuby работают, используя потоки в C#.Синхронизация связи потоков?
Кроме того, я полностью отдаю себе отчет в том, что C# имеет встроенную поддержку возврата доходности, я просто немного кручусь.
Я думаю, это какой-то бедный mans coroutines, удерживая несколько призов в живых с помощью потоков. (Даже если ни один из callstacks не должны выполняться одновременно)
Идея такова:
- Потребитель поток запрашивает значение
- Рабочий поток обеспечивает значение и дает обратно в потребитель нить
- Повторите до тех пор пока рабочий поток выполняется
Итак, что было бы правильным способом сделать следующее?
//example
class Program
{
static void Main(string[] args)
{
ThreadedEnumerator<string> enumerator = new ThreadedEnumerator<string>();
enumerator.Init(() =>
{
for (int i = 1; i < 100; i++)
{
enumerator.Yield(i.ToString());
}
});
foreach (var item in enumerator)
{
Console.WriteLine(item);
};
Console.ReadLine();
}
}
//naive threaded enumerator
public class ThreadedEnumerator<T> : IEnumerator<T>, IEnumerable<T>
{
private Thread enumeratorThread;
private T current;
private bool hasMore = true;
private bool isStarted = false;
AutoResetEvent enumeratorEvent = new AutoResetEvent(false);
AutoResetEvent consumerEvent = new AutoResetEvent(false);
public void Yield(T item)
{
//wait for consumer to request a value
consumerEvent.WaitOne();
//assign the value
current = item;
//signal that we have yielded the requested
enumeratorEvent.Set();
}
public void Init(Action userAction)
{
Action WrappedAction =() =>
{
userAction();
consumerEvent.WaitOne();
enumeratorEvent.Set();
hasMore = false;
};
ThreadStart ts = new ThreadStart(WrappedAction);
enumeratorThread = new Thread(ts);
enumeratorThread.IsBackground = true;
isStarted = false;
}
public T Current
{
get { return current; }
}
public void Dispose()
{
enumeratorThread.Abort();
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
if (!isStarted)
{
isStarted = true;
enumeratorThread.Start();
}
//signal that we are ready to receive a value
consumerEvent.Set();
//wait for the enumerator to yield
enumeratorEvent.WaitOne();
return hasMore;
}
public void Reset()
{
throw new NotImplementedException();
}
public IEnumerator<T> GetEnumerator()
{
return this;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this;
}
}
Идеи?
Ваш код выглядит в целом правильным. Однако я не уделял слишком много времени, так что могут быть небольшие ошибки, но в целом хорошо выглядит. Вы видите какие-то проблемы с этим? Каков твой вопрос? –
Основной вопрос: есть ли лучший способ выполнить то же самое без использования встроенных машин возврата C# yield ?. Что касается кода, он зависает в некоторых случаях и работает крайне плохо, если вы вставляете счетчики. Я не знаю, когда дело доходит до резьбы, поэтому я не совсем понимаю, что делать дальше –