2017-07-07 10 views
0

にThread.Join(タイムラプス)を変換します。つまり私は次のコードを持っている同等の非スレッドパターン

Thread validationThread = new Thread(DoAsyncValidationMethod); 

validationThread.Start(threadParams); 

bool isAborted = false; 

int timeLeft = 5000; 

// wait for thread terminates itself 
if (!validationThread.Join(timeLeft)) 
{ 
    // timeout, abort thread 
    validationThread.Abort(); 
    isAborted = true; 
} 

を、私は(指定時間経過で完了することになっているいくつかの仕事をやっています5000ms)。完了したかどうかにかかわらず、スレッドのアプローチは、開始から5秒以内にコードが返ることを保証します。

これをasync/awaitパターンで実行する方法はありますか?スレッドは単にトリックのために使用されているので、他に取り組むべきアプローチはありますか?

よりエレガントでシンプルな方が良いでしょう。 ありがとうございました。

+0

史上かつて 'Thread.Abortを()'を呼び出すことはありませんしてください。アボートを呼び出すと、実行中の.NETの状態が破損し、他のすべてのスレッド**の結果が信頼できなくなります。 – Enigmativity

答えて

2

私のプロジェクトで使用したコードです。

さらに、Task.WhenAny(param Task[] task) method on MSDNをご覧ください。完了したタスクを返します。

var timeout = 5000; 
var task = Task.Run(() => { 
    Thread.Sleep(new Random().Next(3000, 7000));//Running time simulation! 
    return "Say my name!";//Breaking Bad! 
}); 
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) { 
    // Task completed within timeout. 
    // What if the task is faulted or canceled. 
    // I did not supply a cancellation token but it can easily be added 
    // We re-await the task so that any exceptions/cancellation is rethrown. 
    await task; 
} 
else { 
    // timeout/cancellation logic 
} 
+0

Emrah、ありがとう、第二のタスクのパラメータをかなり賢い。 – Alex

+0

@Alex、私はそれが助けて欲しい!私はタイトなループでこのコードを実行しているかどうかはわかりませんが、これまで問題なく使用しています(* 'ω' *) –

+0

@EmrahSüngü - 'new Random()。Next(3000,7000)'ループは悪い考えかもしれません。 – Enigmativity

0

これは、Microsoftのリアクティブフレームワーク(NuGet "System.Reactive")でうまく実行できます。次に、これを行うことができます:

IObservable<bool> query = 
    Observable.Amb(
     Observable.Timer(TimeSpan.FromSeconds(5.0)).Select(_ => false), 
     Observable.Start(() => DoAsyncValidationMethod()).Select(_ => true)); 

IDisposable subscription = 
    query.Subscribe(flag => 
    { 
     /* `true` succeeded, `false` timed out */ 
    }); 
+0

なぜ落選ですか?これはうまく動作します。このコードの問題点は何ですか? – Enigmativity

+0

UnityプロジェクトでReactiveソリューションを使い始めました。思考スタイルは違うけど楽しいです! –

+0

@EmrahSüngü - これは一般にTPLよりもはるかに強力です。 – Enigmativity

2

CancellationTokenSourceを使用してください。ソースはCancellationTokensの工場です。あなたはきちんとした方法でその処理を取り消すことができるようにしたいすべての人にこのトークンを渡します。 CancellationTokenがあるすべてのプロセスを同じCancellationTokenSourceから取り消したい場合は、CancellationTokenSourceにすべてのプロセスにキャンセルを送信し、このソースからのトークンを持つすべてのプロセスをキャンセルしてください。

また、CancellationTokenSourceにはCancelAfter(some timeout)があります。

あなたのプロセスのスターターがcancelationTokenを与えるようにして、プロセスの初心者が1回の呼び出しでキャンセルしたいプロセスを決定できるようにすることをお勧めします。

public async Task<MyResult> MyProcessAsync(CancellationToken cancellationToken, ...) 
{ 
    // do something lengthy processing, without await, regularly check if Cancellation requested 
    while (stillProcessing) 
    { 
     cancellationToken.ThrowIfCancellationRequested(); 
     ... // process 
    } 

    // do some processing with async-await: 
    await myDbContext.SaveChangesAsync(cancellationToken); 
} 

使用法:一つだけCancelltionTokenSourceが使用されている

private async Task LengthyProcessing(...) 
{ 
    CancellationTokenSource tokenSource = new CancellationTokenSource(); 
    tokenSource.CancelAfter(TimeSpan.FromSeconds(5)); 

    CancellationToken myCancellationToken = tokenSource.Token 
    try 
    { 
     // Start one task, don't await yet: 
     var myTask = await MyProcessAsync(myCancellationToken, ...) 
     // during processing there will be regular check if cancellation requested 
     // meanwhile, whenever myTask has to await, I can do some processing 
     // I'll have to check for cancellation regularly also: 

     while(...) 
     { 
      myCancellationToken.ThrowIfCancellationRequested(); 
      DoSomeProcessing(); 
      ... 
     } 

     MyResult result = await myTask; 
     // if here, not cancelled. can use Result: 
     ProcessResult(result); 
    } 
    catch (OperationCanceledException exc) 
    { 
     ProcessOperationCanceled(); 
    } 
} 

注意。このソースが何かをキャンセルする必要があると考えるたびに、このソースからのトークンを持つすべてのスレッドにcancellationrequestについての通知が送られます。

CancellationToken.ThrowIfCancellationRequested()で例外処理を使用する代わりに、bool CancellationToken.IsCancellationRequestedを使用することを検討してください。あなたが強制的にアプリの外にクラッシュしようとしている場合を除き

MSDN how to cancel a task and its children

+0

@ Harald-この回答に感謝します。このアプローチは新しいスレッドを作成しません、それはすべてメインスレッドで発生します、正しいですか? – Alex

+0

心配しないで、私はリンクのコードを見て、タスクがあなたのコードの '... // process'セクションで使用されることに気付きました。 – Alex

関連する問題