[解決済み] タスクの同期継続を防ぐには?
質問
ライブラリ(ソケットネットワーク)のコードがあり、そのコードは
Task
-をベースにした API があります。
TaskCompletionSource<T>
. しかし、TPLには、同期的な継続を防ぐことができないように見えるという厄介な点があります。私なら
のように
ができるようにしたいのは、どちらかです。
-
を伝える
TaskCompletionSource<T>
でアタッチすることを許可してはいけません。TaskContinuationOptions.ExecuteSynchronously
または -
結果を設定する (
SetResult
/TrySetResult
) を指定する方法でTaskContinuationOptions.ExecuteSynchronously
は無視され、代わりにプールを使用します。
具体的には、受信したデータは専用のリーダーで処理され、もし呼び出し側が
TaskContinuationOptions.ExecuteSynchronously
でアタッチできる場合、リーダーをストールさせることができます (これは自分だけでなく、他の人にも影響します)。以前は、この問題を回避するために
を検出するハッカーで対処していました。
が存在するかどうかを検出し、もし存在するならば、その補完を
ThreadPool
しかし、これは、呼び出し元がワークキューを飽和させている場合、補完がタイムリーに処理されないため、重大な影響を及ぼします。もし、呼び出し元が
Task.Wait()
(など)を使用している場合、本質的にデッドロックが発生します。同様に、これは読者がワーカーを使用するのではなく、専用のスレッド上にある理由です。
私が TPL チームに口うるさく言う前に: 私はオプションを見逃していますか?
重要なポイントです。
- 外部の呼び出し元にスレッドを乗っ取られないようにしたい
-
私は
ThreadPool
は、プールが飽和したときに動作する必要があるため、実装として
以下の例は出力を生成します(タイミングにより順序が異なる場合があります)。
Continuation on: Main thread
Press [return]
Continuation on: Thread pool
問題は、ランダムな呼び出し元が "メインスレッド" で継続を得ることに成功したという事実です。実際のコードでは、これは主要な読者に割り込むことになります。
コードです。
using System;
using System.Threading;
using System.Threading.Tasks;
static class Program
{
static void Identify()
{
var thread = Thread.CurrentThread;
string name = thread.IsThreadPoolThread
? "Thread pool" : thread.Name;
if (string.IsNullOrEmpty(name))
name = "#" + thread.ManagedThreadId;
Console.WriteLine("Continuation on: " + name);
}
static void Main()
{
Thread.CurrentThread.Name = "Main thread";
var source = new TaskCompletionSource<int>();
var task = source.Task;
task.ContinueWith(delegate {
Identify();
});
task.ContinueWith(delegate {
Identify();
}, TaskContinuationOptions.ExecuteSynchronously);
source.TrySetResult(123);
Console.WriteLine("Press [return]");
Console.ReadLine();
}
}
どのように解決するのですか?
.NET 4.6での新機能です。
.NET 4.6では、新しい
TaskCreationOptions
:
RunContinuationsAsynchronously
.
プライベートフィールドにアクセスするためにReflectionを使用することを望んでいるのですから...
TCSのTaskをマークするのは
TASK_STATE_THREAD_WAS_ABORTED
フラグを付けると、すべての連続がインライン化されないようになります。
const int TASK_STATE_THREAD_WAS_ABORTED = 134217728;
var stateField = typeof(Task).GetField("m_stateFlags", BindingFlags.NonPublic | BindingFlags.Instance);
stateField.SetValue(task, (int) stateField.GetValue(task) | TASK_STATE_THREAD_WAS_ABORTED);
編集します。
Reflectionのemitを使う代わりに、式を使うことを提案します。これはより可読性が高く、PCLと互換性があるという利点があります。
var taskParameter = Expression.Parameter(typeof (Task));
const string stateFlagsFieldName = "m_stateFlags";
var setter =
Expression.Lambda<Action<Task>>(
Expression.Assign(Expression.Field(taskParameter, stateFlagsFieldName),
Expression.Or(Expression.Field(taskParameter, stateFlagsFieldName),
Expression.Constant(TASK_STATE_THREAD_WAS_ABORTED))), taskParameter).Compile();
Reflectionを使用せず。
もし誰かが興味を持っているなら、私はこれをReflectionなしで行う方法を見つけ出したのですが、それは同様に少し"汚い"で、もちろん無視できないperfのペナルティを伴います。
try
{
Thread.CurrentThread.Abort();
}
catch (ThreadAbortException)
{
source.TrySetResult(123);
Thread.ResetAbort();
}
関連
-
解決済み] Critical error detected c0000374 - C++ dll returns pointer off allocated memory to C# [解決済み] Critical error detected c0000374 - C++ dll returns pointer off allocated memory to C#.
-
[解決済み] enumを列挙するには
-
[解決済み] intをenumにキャストするにはどうすればよいですか?
-
[解決済み] C#で文字列のエンコーディングを手動で指定せずに、一貫性のあるバイト表現を得るには?
-
[解決済み] DateTime型の誕生日から年齢を計算するにはどうしたらいいですか?
-
[解決済み] Microsoft Officeをインストールせずに、C#でExcel(.XLSおよび.XLSX)ファイルを作成するにはどうすればよいですか?
-
[解決済み] async」と「await」の使い方とタイミング
-
[解決済み] ランダムな英数字の文字列を生成するにはどうすればよいですか?
-
[解決済み] C#で同期メソッドから非同期メソッドを呼び出すには?
-
[解決済み] 私のインターフェースがTaskを返さなければならない場合、操作不要の実装を持つための最良の方法は何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】統合マネージドパイプラインモードで適用されないASP.NETの設定が検出された
-
[解決済み】"The ConnectionString property has not been initialized "を修正する方法
-
[解決済み】「入力文字列が正しい形式ではありませんでした」エラーの解決方法は?[重複しています]。
-
[解決済み】C# ASP.NET使用時に「WebClientのリクエスト中に例外が発生しました。
-
[解決済み] DBNullから他の型にオブジェクトをキャストすることができない
-
[解決済み】クロススレッド操作が有効でない。作成されたスレッド以外のスレッドからアクセスされたコントロール
-
[解決済み】OnCollisionEnter2Dが実行されない?
-
[解決済み】2年前のMSDateを把握する【クローズド
-
[解決済み] ...基礎となる接続は閉じられました。予期しないエラーが受信で発生しました
-
[解決済み】Microsoft.Extensions.LoggingからILoggerを解決することができない