Synchronizing thread communication?

Posted by Roger Alsing on Stack Overflow See other posts from Stack Overflow or by Roger Alsing
Published on 2010-04-22T13:19:10Z Indexed on 2010/04/22 13:23 UTC
Read the original article Hit count: 322

Filed under:
|
|
|
|

Just for the heck of it I'm trying to emulate how JRuby generators work using threads in C#.

Also, I'm fully aware that C# haas built in support for yield return, I'm just toying around a bit.

I guess it's some sort of poor mans coroutines by keeping multiple callstacks alive using threads. (even though none of the callstacks should execute at the same time)

The idea is like this:

  • The consumer thread requests a value
  • The worker thread provides a value and yields back to the consumer thread
  • Repeat untill worker thread is done

So, what would be the correct way of doing the following?

//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;
    }
}

Ideas?

© Stack Overflow or respective owner

Related posts about generator

Related posts about c#