开发者

Design alternatives to thread implementation of coroutines for converting a push method into a pull method

I have a collection class that holds lots of different types of data in a compressed format. In order to enumerate over all of the values in the collection is has an Execute(Query, IDataWriter) method. You pass it a query that defines what data you want, and then for each piece of matching data it calls a method on the IDataWriter object you pass in.

The IDataWriter interface has 15 different methods, one for each different data type in the collection. Now I need to commit this data to the database and I want to be able to implement IEnumerator<SqlDataRecord> to commit stuff to the database. The problem comes in how to convert calling Execute which dumps a ton of data into the IDataWriter object(push), to a pull method so that the IEnumerator's MoveNext and Current can be used.

I have looked at Coroutines and fibers, but none of the examples I have found seem like they would work for an existing method (Execute in my case) that internally knows nothing of the corountine. So my plan in pseudo开发者_开发知识库code is to do the following using Threads and manual synchronization.

The Execute method would be running in a seperate Thread and I would manually wait and signal it inside each IDataWriter method

class EnumeratorAdapterObject : IEnumerator<SqlDataRecord>, IDataWriter
{

public EnumeratorAdapterObject(Store storeObject)
{
    workerThread = new Thread(storeObject.Execute(query, this));
}

public bool MoveNext()
{
    if (firstTimeCalled)
    {
        start worker thread
    }
    else
    {
        signal resume
    }
    block for either a call into an Add method or the Execute thread finishes

    if (not anything buffered)
        return false
    else
        return true
}


// 14 other methods like this implemented in IDataWriter, each with different types
public void Add_Decimal(IntvlDataHeader header, decimal data)
{
    buffer field of current SqlDataRecord = generate record;

    signal main thread
    wait for resume signal
}

public SqlDataRecord Current
{
    get { return buffer field of current SqlDataRecord; }
}

}

Does this look like a good approach? Does anyone know of any examples or questions that already implement this?

Or would there be a way to take advantage of any of the new 4.0 features? I thought about using a blocking concurrent collection with a limit of 1 thing in it, but then how would the consumer(the IEnumerator's MoveNext) know when the other thread is finished adding stuff?


Rather than doing manual Thread creation and synchronization with Signal/Wait I figured out that I can use Blocking collection with a call to CompleteAdding() when done. The following is a quick example, for my problem above I will wrap this in an object that implements IEnumerator<SqlDataRecord> and IDataWriter, so instead of the GenerateStuff call I will be calling Execute and the Add_* methods will be the ones calling col.Add(new SqlDataRecord(....))

static void Main(string[] args)
{
    var col = new BlockingCollection<int>(1);

    Task.Factory.StartNew(
        () =>
        {
            GenerateStuff(col);
            col.CompleteAdding();
        });

    while (!col.IsCompleted)
    {
        Thread.Sleep(100);

        int result;
        if (!col.TryTake(out result, -1))
        {
            break;
        }
        Console.WriteLine("Got {0}", result);
    }

    Console.WriteLine("Done Adding!");
}

static void GenerateStuff(BlockingCollection<int> col)
{
    for (int i = 0; i < 10; i++)
    {
        Thread.Sleep(10);
        Console.WriteLine("Adding {0}", i);
        col.Add(i);
        Console.WriteLine("Added {0}", i);
    }
}

This also has the advantage that the worker thread that is running the Execute will be generating the next result concurrently with the IEnumerator returning Current and the sql code doing whatever it does to commit the data. With the manual thread signalling only one thread would ever run at a time.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜