Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there anyway to end a delegate if I no longer care about the result?

I have a piece of code that searches several third party APIs. I have the searches split into 2 groups based on the search criteria. I start both searches because each search is quite timely, but if the first group of searches results in an match I don't want to wait around for the second search group to finish. So basically what I have is:

Dictionary<string, string> result = null;
NameSearchDelegate nameDel = new NameSearchDelegate(SearchByName);
IAsyncResult nameTag = nameDel.BeginInvoke(name, null, null);
if(!string.IsNullOrWhiteSpace(telNum))
{
    result = SearchByTelNum(telNum);//Will return null if a match is not found
}
if(null == result)
{
    result = nameDel.EndInvoke(nameTag);
}
//End the delegate to prevent memory leak
//else
//{
//    nameDel.EndInvoke(nameTag)
//}
return result;

So I want to start the SearchByName before I call SearchByTelNum in case it does not find a match, however if it does find a match I don't want to have to wait for SearchByName to finish before returning the match. Is there any way to simply end or cancel that delegate if I no longer need its result?

like image 979
John Loomis Avatar asked Nov 13 '22 12:11

John Loomis


1 Answers

I was able to solve my problem using System.ComponentModel.BackgroundWorker. I wasn't necessarily using it in the way it is intended to be used but it was able to do what I needed. So basically what my new code looks like is:

Dictionary<string, string> telResult = null,
                           nameResult = null;

BackgroundWorker bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += (obj, e) => nameResult = SearchByName(name, bw);
bw.RunWorkerAsync();

if(!string.IsNullOrWhiteSpace(telNum))
    telResult = SearchByTelNum(telNum);//Will return null if a match is not found

if(telResult != null)
{
    bw.CancelAsync;
    return telResult;
}

bool hasTimedOut = false;
int i = timeOutCount;
while (bw.IsBusy && !hasTimedOut)
{
    System.Threading.Thread.Sleep(500);
    if (0 == --i) hasTimedOut = true;
}

return nameResult;

And to make sure there are no bugs, I had to make sure that SearchByName periodically checks if bw.CancellationPending equals true, and ends the method in that case. CancelAsync does not end the worker thread, it simply alerts the worker thread that caller thread has canceled it.

Also I could have simply used

while(bw.IsBusy) System.Threading.Thread.Sleep(500)

to wait for the method to complete, but if something bad happens in SearchByName you could end up waiting forever in an infinite loop. This way I can set an amount of time before the method is considered to have timed out and the caller thread just goes on with life. In this case, since I check bw.IsBusy every .5 seconds, the timeout length is equal to timeOutCount / 2 seconds.

Ok I think I have thoroughly answered my own question.

like image 169
John Loomis Avatar answered Nov 15 '22 06:11

John Loomis