0

I'm using multi-threaded database query to retrieve several data tables at once. I've used a list which is locked...and once all the callbacks are returned, I want to return the list. I want to know how to wait for all the callbacks to finish.

private Object TableLock = new Object();
private List<DataTable> tables_from_callback = new List<DataTable>();

private void ExecReaderHandleCallback(IAsyncResult result)
{
    SqlCommand command = (SqlCommand)result.AsyncState;
    SqlDataReader reader = command.EndExecuteReader(result);
    DataTable dt = new DataTable();
    dt.Load(reader);
    lock (TableLock)
    {
        tables_from_callback.Add(dt);
    }

}

public List<DataTable> BegExecReader(String query, int query)
{
    conn = new SqlConnection(connectionString);
    try
    {
        conn.Open();
        WaitHandle[] waitHandles = new WaitHandle[query];
        IAsyncResult[] results = new IAsyncResult[query];
        SqlCommand[] cmds = new SqlCommand[query];
        for (int i = 0; i < query; i++ )
        {
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = conn;
            cmd.CommandText = query;
            cmd.CommandType = CommandType.Text;
            cmd.CommandTimeout = queryTIMEOUT;

            AsyncCallback callback = new AsyncCallback(ExecReaderHandleCallback);
            cmd.BeginExecuteReader(callback, cmd);
            cmds[i] = cmd;
        }

        /* ????
        here I need to wait for the callbacks to finish
        HOW?
        ??????? */
        return tables_from_callback;
    }
    finally
    {
        conn.Close();
    }
}

I've done something similar without using the callbacks where

IAsyncResult result = cmd.BeginExecuteReader();
results[i] = result;
waitHandles[i] = result.AsyncWaitHandle;
...
WaitHandle.WaitAll(waitHandles);

but now I MUST use the callback so I do not have the wait handles. Any help would be appreciated.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
max
  • 9,708
  • 15
  • 89
  • 144
  • You could probably use a Mutex. (You can also use a variable in a more global scope; however, that's probably a little cheesy.) – Markus Jun 19 '14 at 21:10
  • A Semaphore would probably work too...didn't post as answer because I don't have an example readily available. – Markus Jun 19 '14 at 21:15
  • hey folks, that 'lock' statement in my code is the c# equivalent of mutex/semaphore in c++. The problem is waiting for the asynchronous callbacks. – max Jun 19 '14 at 22:18
  • I realize that...see my example, which somewhat simulates your situation. – Markus Jun 19 '14 at 22:58
  • there may be a better way to do this...I am just answering your question. Whether or not the methods are appropriate for your given situation is probably a matter of opinion. – Markus Jun 19 '14 at 23:04

1 Answers1

0

A cheesy way to do this is to use a variable that both contexts have access to. By context, I mean the caller that passes the callback and the callback itself.

    static void Main(string[] args)
    {
        int x = 1;
        Task.Run(() =>
        {
            Thread.Sleep(5000);
            Console.WriteLine("Yay!");
            x = 0;
        });

        while (x != 0) { Thread.Yield(); }

        Console.WriteLine("Done");
        Console.ReadKey(true);
    }

I'm using Task.Run to simulate your callback situation; however, the principle still applies in the case of a callback...the difference is that you would use a class-level variable or (yikes) a static variable. You could also something like a Semaphore as long as the Semaphore is not signaled right away...like this.

    static void Main(string[] args)
    {
        Semaphore s = new Semaphore(1, 2);
        Task.Run(() =>
        {
            s.WaitOne();
            Thread.Sleep(5000);
            Console.WriteLine("Yay!");
            s.Release();
        });

        Thread.Sleep(100);
        s.WaitOne();

        Console.WriteLine("Done");
        Console.ReadKey(true);
    }
Markus
  • 761
  • 3
  • 6
  • The number of times the semaphore can be incremented is query + 1, I believe, in your example. – Markus Jun 19 '14 at 23:06