次のデータグラム ソケット操作を TPL でラップして API をクリーンアップし、クラスと同じようにasync
and とうまく動作するようにしたいと思います。await
StreamSocket
public static async Task<bool> TestAsync(HostName hostName, string serviceName, byte[] data)
{
var tcs = new TaskCompletionSource<bool>();
var socket = new DatagramSocket();
socket.MessageReceived += (sender, e) =>
{
var status = false; // Status value somehow derived from e etc.
tcs.SetResult(status);
};
await socket.ConnectAsync(hostName, serviceName);
var stream = await socket.GetOutputStreamAsync();
var writer = new DataWriter(stream);
writer.WriteBytes(data);
await writer.StoreAsync();
return tcs.Task;
}
難点は、クラスをイベント非同期パターンと新しいパターンの奇妙な寄せ集めにMessageReceived
変えるイベントです。とにかく、後者に適合するようにハンドラーを適応させることができるので、それほど怖くありません。DatagramSocket
async
TaskCompletionSource<T>
エンドポイントがデータを返さない限り、これはかなりうまくいくようです。MessageReceived
ハンドラーに関連付けられたタスクが完了しないため、から返されたタスクがTestAsync
完了しません。
この操作を適切にラップしてタイムアウトとキャンセルを組み込む正しい方法は何ですか? 後者の引数を取るためにこの関数を拡張したいのですCancellationToken
が、どうすればよいでしょうか? 私が思いついた唯一のことはTask.Delay
、次の行に沿ってこれら 2 つの動作をサポートするために、タイムアウト値とキャンセル トークンを渡す追加の「監視」タスクを作成することです。
public static async Task<bool> CancellableTimeoutableTestAsync(HostName hostName, string serviceName, byte[] data, CancellationToken userToken, int timeout)
{
var tcs = new TaskCompletionSource<bool>();
var socket = new DatagramSocket();
socket.MessageReceived += (sender, e) =>
{
var status = false; // Status value somehow derived from e etc.
tcs.SetResult(status);
};
await socket.ConnectAsync(hostName, serviceName);
var stream = await socket.GetOutputStreamAsync();
var writer = new DataWriter(stream);
writer.WriteBytes(data);
await writer.StoreAsync();
var delayTask = Task.Delay(timeout, userToken);
var t1 = delayTask.ContinueWith(t => { /* Do something to tcs to indicate timeout */ }, TaskContinuationOptions.OnlyOnRanToCompletion);
var t2 = delayTask.ContinueWith(t => { tcs.SetCanceled(); }, TaskContinuationOptions.OnlyOnCanceled);
return tcs.Task;
}
MessageReceived
ただし、これには、遅延タスクとハンドラーの間の潜在的な競合状態を含む、あらゆる種類の問題があります。このアプローチを確実に機能させることはできませんでした。さらに、スレッドプールの非効率的な使用と同様に、とてつもなく複雑に思えます。手間がかかり、エラーが発生しやすく、頭が痛くなります。
補足:DatagramSocket
一般的に API に混乱しているのは私だけですか? IAsyncAction
WinRT モデルと TPL にトリッキーな EAP が組み込まれた見苦しい集合体のように見えるだけでなく、名前が付けられたメソッドを含む UDP など、基本的にコネクションレスのプロトコルを表すことを意図した API にあまり満足していませんConnectAsync
。これは私には矛盾しているように思えます。