-1

I have the following code:

//requests bar data
Task.Run( () => CONNECTION.ReqBarData()).Wait();

//the bars arrive on different thread here
virtual override void OnBar()
{
 //takes a while till all bars arrive
}

The problem is that i need to wait on all bars to arrive in the OnBar() method and my code above is only waiting on the call to ReqBarData(). In other words ReqBarData() takes only afew milliseconds but the OnBar() method takes 30 or more seconds. i also want my UI to be responsive while i wait for the OnBar() to finish. thanks

AlgoAlpha
  • 51
  • 10
  • Please provide more infomation on how the first line of code and the OnBar function are related It is not exactly clear how the two functions relate to eachother. It looks like they are a [Event-based Asynchronous Pattern](https://msdn.microsoft.com/en-us/library/ms228969(v=vs.110).aspx). If it is, take a look at [this MSDN page](https://msdn.microsoft.com/en-us/library/hh873178(v=vs.110).aspx#Anchor_1) – Scott Chamberlain Jun 30 '16 at 13:51
  • If you have long running method in `OnBar` and you receive that in UI thread somehow (via invoke?) then you can use same `Task.Run` to run that code asynchronously. You are not doing that probably because you have some problem. Tell us. – Sinatr Jun 30 '16 at 13:56
  • You should virtually never call `Wait()`; have you tried using `await` instead? – Marc Gravell Jun 30 '16 at 13:57
  • @ScottChamberlain ..Thank you for info .. ReqBarData() requests bars from the broker and the broker sends back the information via the OnBar() method. i know the way the API implements this is by using events but not sure about anything else – AlgoAlpha Jun 30 '16 at 14:00
  • @Sinatr .. i dont call the OnBar() method .. this method only receives the bars i only process them .. i cannt use task.run => OnBar() ... – AlgoAlpha Jun 30 '16 at 14:02
  • *"i cannt use task.run => OnBar()"*, but you can do `void OnBar() => Task.Run(() => {..here is the code you have now in OnBar..});`. Then your UI is *perfectly responsive*... – Sinatr Jun 30 '16 at 14:08
  • @Sinatr not sure i understand your code .. can you please explain further ? – AlgoAlpha Jun 30 '16 at 14:14

2 Answers2

1

I am going on the assumption that OnBar does not actaully take 30 seconds to run, what it does is it takes 30 seconds to start after calling ReqBarData. If that is true what you really have is a Event-based Asynchronous Pattern, the easiest way to handle what you want to do is convert it to a Task-based Asynchronous Pattern.

Because you did not provide a Minimal, Complete, and Verifiable example I am going to have to make some changes to how I think your program works. You will need to update your question with a proper example if you would like code closer to what you really have. I have made an assumption that ReqBarData has a overload that takes in a object state parameter which will be passed to OnBar and OnBar also gets passed the list of objects that it was waiting for.

public Task<List<Bar>> RequestDataAsync()
{
    var tcs = new TaskCompletionSource<List<Bar>>();
    //This does not need to be on a separate thread, it finishes fast.
    CONNECTION.ReqBarData(tcs);
    return tcs.Task;
}

virtual override void OnBar(List<Bar> someBars, object stateInfo)
{
    //We get our TaskCompletionSource object back from the state paramter
    var tcs = (TaskCompletionSource<List<Bar>>)stateInfo;

    //we set the result of the task.
    tcs.SetResult(someBars);
}

To use it without locking up the UI you simply call the function and await it using async/await

public async void Button1_Click(object sender, EventArgs args)
{
    await LoadData();
}

private async Task LoadData()
{
    List<Bar> bars = await myConnectionClass.RequestDataAsync();
    SomeBinding.DataSource = bars;
}
Community
  • 1
  • 1
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • thanks alot for providing sample code .. ReqBarData(Contract c) where c is the contract im requesting bars on... OnBar() returns the bars one at a time with an assigned reqID which i keep track of in code. the bars start coming in instantly but if the request is for a large # of bars then it might take 10-30 sec's .. and i want to wait for all of them to come in. ill try your code and see if i can get it to work – AlgoAlpha Jun 30 '16 at 19:52
0

OnBar() method takes 30 or more seconds.

If this method is called in UI thread, then you can use Task.Run to run it in some other thread (similar to what you already do, therefore my comments as it's not clear if this is a case).

Change

virtual override void OnBar()
{
    ... whatever
}

to

virtual override void OnBar() => Task.Run(() =>
{
    ... whatever
});

But more likely you have to simply use async:

async void SomeEventHandlerToExampleButtonClick(object sender, SomeEventArgs e)
{
    await Task.Run(() => CONNECTION.ReqBarData());
    ... // you are here after ReqBarData() is finished and you are not blocking UI so far
}
Sinatr
  • 20,892
  • 15
  • 90
  • 319
  • OnBar is a callback method, think of it as somewhere else in the code the OP has `CONNECTION.DataAvailable += OnBar` the OP wants to wait till the work is done, this is a job for a `TaskCompletionSource` – Scott Chamberlain Jun 30 '16 at 14:51
  • @ScottChamberlain, *"OnBar is a callback method"* - how do you know? As for completing, I know `async/await` pattern like this to call `Action<>` methods and don't block UI, but I have no clue what is `TaskCompletionSource`. What should I fix (where is the problem)? Perhaps you can post another answer? – Sinatr Jun 30 '16 at 14:57
  • @ScottChamberlain thank for the info .. i looked into TaskCompletionSource and saw some examples [Here](http://stackoverflow.com/questions/15316613/real-life-scenarios-for-using-taskcompletionsourcet) but im still not clear on how to use it in my case .. would you be able to post some sample code that would relate to my code. thanks – AlgoAlpha Jun 30 '16 at 18:12