2

.Net 4.5 には、キャンセル トークンを監視しながらストリームから非同期的に読み取る Stream クラスのメソッドが存在します。

ReadAsync : 
       buffer:byte[] * 
       offset:int * 
       count:int * 
       cancellationToken:CancellationToken -> Task<int>

別のスレッドが最初にキャンセル トークンをトリガーしてからストリームを閉じる必要がある場合、ReadAsync が例外をスローする前に読み取りスレッドがキャンセルされることが保証されますか?

.Net 4.0 フレームワークと F# 非同期ワークフローを ReadAsync (監視対象のキャンセル トークンを受け入れるオーバーロードがない) なしで使用して、どうにかしてこの保証を達成できますか?

4

3 に答える 3

3

この特定のオーバーロードは、複数のタスクをチェーン化しない限り、基本的には役に立ちません。メソッド呼び出しcancellationTokenへのエントリ時にのみチェックされ、基になる呼び出しの実行中はチェックされません。ReadAsyncStream.BeginRead

ILSpyからダンプされたコード:

public virtual Task<int> ReadAsync(byte[] buffer,
                                   int offset,
                                   int count,
                                   CancellationToken cancellationToken)
{
    if (!cancellationToken.IsCancellationRequested)
        return this.BeginEndReadAsync(buffer, offset, count);
    return Task.FromCancellation<int>(cancellationToken);
}

ご覧のとおり、は通話にcancellationToken転送されず、次の観点から実装されているだけです。BeginEndReadAsyncBeginEndReadAsyncStream.BeginRead

private Task<int> BeginEndReadAsync(byte[] buffer, int offset, int count)
{
    return TaskFactory<int>.FromAsyncTrim<Stream, Stream.ReadWriteParameters>(
        this,
        new Stream.ReadWriteParameters
        {
            Buffer = buffer,
            Offset = offset,
            Count = count
        },
        (Stream stream, Stream.ReadWriteParameters args, AsyncCallback callback, object state) =>
            stream.BeginRead(args.Buffer, args.Offset, args.Count, callback, state),
        (Stream stream, IAsyncResult asyncResult) =>
            stream.EndRead(asyncResult)
    );
}

この時点で保証されるのは、派生したストリームタイプによって作成されたものだけであり、タイプごとに異なります。

これは現在の.Net4.5ビットに基づいており、実装はもちろん将来変更される可能性があることに注意してください。

于 2012-09-26T19:51:38.793 に答える
1

/を使用Task.IsCanceledしてタスクを実行する前に確認できます。ResultRunSynchronously

次にいくつかのサンプルコードを示します。

use stream = new MemoryStream(Array.init 1000 (fun i -> byte (i % int Byte.MaxValue)))
use waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset)
use cts = new CancellationTokenSource()
let thread = Thread(fun () -> 
  Thread.Sleep(1000)
  let buf = Array.zeroCreate 100
  let task = stream.ReadAsync(buf, 0, buf.Length, cts.Token)
  if not task.IsCanceled then task.RunSynchronously()
  waitHandle.Set() |> ignore)
thread.Start()
cts.Cancel()
waitHandle.WaitOne() |> ignore

ただし、ReadAsync開始すると、タスクがキャンセルされたことを示すメッセージスローされます。AggregateException

于 2012-09-26T19:51:46.390 に答える
0

私の知る限り、ミューテックスを使用してストリームを保護し、キャンセルトークンを使用して保留中のキャンセルについてスレッドをチェックする必要があります。これを処理する非同期プリミティブはありませStreamん。

于 2012-09-27T15:32:59.560 に答える