-1

I understand how I can await on library code to wait for a network request or other long-running action to complete, but how can I await on my own long-running action without busy waiting?


This is the busy-waiting solution. How can I make it event-driven?

public async Task<DataBlock> ClickSend() {
    // await until someone calls DataReceived()
    while (_Block == null) {
        await Task.Yield();
    }
    return _Block;
}

// Something external calls this function.
// Once called, ClickSend should complete with this data.
public void DataReceived(DataBlock data_block) {
    _Block = data_block;
}
DataBlock _Block = null;

(This question is completely different from How do I await events in C#? which is asking how to await on event handlers, but very similar to Promise equivalent in C#.)

idbrii
  • 10,975
  • 5
  • 66
  • 107
  • @PeterDuniho: None of the answers on [How do I await events in C#?](https://stackoverflow.com/questions/27761852/how-do-i-await-events-in-c) suggest using a `TaskCompletionSource`. I agree that the the two questions appear to be asking the same question, but the intent is quite different. I don't care about the async behaviour of the `event` keyword and they don't care about TaskCompletionSource. – idbrii May 26 '21 at 16:59
  • You're right that the answer is very similar to "what is a promise in C#", but it's hard to find that question if you don't know what you're looking for (a promise) and the questions is phrased in terms of another language. I posed this question because it is free of that context so it's more broadly useful. (I don't see any "this may be a duplicate" links that you're referring to -- just your comment.) – idbrii May 26 '21 at 17:19
  • You can see the revision history for the post [here](https://stackoverflow.com/posts/67611867/revisions), which shows the post I mistakenly used for the duplicate target, and then the correct one I added right after. It's unfortunate that I didn't notice the error of the first link, since that would have been the right time for me to fix it as well. – Peter Duniho May 26 '21 at 17:36

1 Answers1

1

Generally in concurrency a "future" is placeholder for a return value and it has an associated "promise" that is fulfilled to pass the final return value.

In C#, they have different names: the future is a Task and the promise is a TaskCompletionSource.

You can create a promise, await on it, and then fulfill it when you get your callback:

TaskCompletionSource<DataBlock> _Promise = new TaskCompletionSource<DataBlock>();

public async Task<DataBlock> ClickSend() {
    DataBlock block = await _Promise.Task;
    return block;
}

public void DataReceived(DataBlock data_block) {
    _Promise.TrySetResult(data_block);
}

Here's an executable example.

idbrii
  • 10,975
  • 5
  • 66
  • 107