Quantcast
Channel: 製造業 スマートDX推進課 スマート工場DIY日記
Viewing all articles
Browse latest Browse all 5

【C#】await を強制的にタイムアウトさせた

$
0
0

前回使用した HidLibraryで信号の取りこぼしが発生し、ReadReportAsync メソッドで永遠に待機しまう事象が発生した為、無理やりタイムアウトさせた話です。
タイムアウトの引数がありますが、上手く動作しません。

Task の CanselAfter も動作しない為(私の使い方が悪かったかもしれません)
苦肉の策で強制的にタイムアウトするようにしました。

どうしてもタスクをタイムアウトさせたい時の参考になれば幸いです。

ソースコード

privateasync Task Timeout(int t, CancellationTokenSource cts)
        {
            for (int i =0; i < t; i +=10)
            {
                await Task.Delay(10);
                if (cts.IsCancellationRequested) return;
            }
        }

        privateasync Hoge()
        {
            var cts =new CancellationTokenSource();
            Task<> t = HogeTask();
            await Task.WhenAny(t, Timeout(1000, cts.Token));
            cts.Cancel();
            cts.Dispose();

            var result;
            if (t.IsCompleted)
            {
                result = t.Result;
                t.Dispose();
            }
            else
            {
                //タイムアウト時の処理return;
            }
        }

解説

Timeoutメソッドは、引数の時間(ms) 待機するだけのメソッドです。

特記事項としては

if (ct.IsCancellationRequested) return;

で、外部からのタスクキャンセルを受け取り、メソッドを終了しています。

 

var cts =new CancellationTokenSource();
Timeout(1000, cts.Token));
cts.Cancel();

キャンセルトークンを Timeoutメソッドへ渡し、タスク処理が終了した際にキャンセルをしています。

 

上記がタイムアウトの前準備で、あとは Task.WhenAnyでいずれかのタスクが完了すれば処理を進行するというプログラムを書けば完成です。

Task<> t = HogeTask();
await Task.WhenAny(t, Timeout(1000, cts.Token));
var result; if (t.IsCompleted) { result = t.Result; t.Dispose(); } else { //タイムアウト時の処理 return; }

タイムアウト時にタスクをDisposeしてませんが(タスクが完了してないのでDispose出来ない)
ガベージコレクションで自動的に破棄されるので、問題はないと思います。

あとがき

無理やり感があるコードですが、これであればどんなタスクでもタイムアウトすることが可能だと思います。

かなりシンプルに実装出来てよかったです。


Viewing all articles
Browse latest Browse all 5

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>