問題タブ [synchronizationcontext]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c# - 表示されている 2 番目のフォームの同期コンテキストを取得する方法
[編集]投稿全体を言い換えて簡略化[/編集]
このブログでは、SynchronizationContext オブジェクトを使用して UI スレッドで Task を実行する例として、次の (少し簡略化しました) を示します。
新しいプロジェクトでこれらの結果を繰り返し、UI を安全に更新することはできますが、現在のプロジェクトでは何らかの理由で (それが機能していたとしても) できません。標準の「間違ったスレッドから UI を更新することはできません」という例外が発生します。
私のコード(MainForm_Load(...)内)は次のようなもので、メインフォームにtextBox1が追加された新しいプロジェクトで機能しますが、現在のプロジェクトでは機能しません:
誰でも何が起こっているのかについて考えを持っています。
[編集]
フォームを使用してユーザーにログイン情報を求めるオブジェクトのインスタンス化にまでさかのぼってエラーをたどりました。エラーは、フォームが表示されている場合にのみ発生します。(そのフォームが発生する前にハードコードされた値を返すとShow
、すべてが正常に機能します)。
新しい質問: 独自のコンストラクターが表示される前に別のフォームを表示する場合、作成中のフォームの SynchronizationContext を取得するにはどうすればよいですか? 何が起こっているかを再現する方法は次のとおりです。
1) 2 つのフォームを作成しTextBox
ます。Button
2) クラスを作成するOwnedBy1Uses2
Form1
:
Form2
:
OwnedBy1Uses2
:
c# - UIアプリケーションでSynchronizationContext.SetSynchronizationContext()を呼び出すのはいつですか?
私はSynchronizationContext
クラスについて学んでいます。SynchronizationContext.SetSynchronizationContext()
WinForm/WPFアプリケーションのコンテキストで呼び出すための一般的な使用シナリオを理解しようとしています。SynchronizationContext
スレッドのを設定するとはどういう意味ですか?いつ、なぜそれをすべきですか?また、設定した場合、いつか設定を解除する必要がありますか?
編集:
彼の答えの中で、@ Hans Passantは、なぜ私が考えているのかと尋ねましたSetSynchronizationContext()
。私が持っているアイデアは、ワーカースレッドにコンテキストを設定して、そのスレッドで実行されているコードが使用するコンテキストを持つようにすることです。
.net - .NET: 特定のスレッドでデリゲートを呼び出すにはどうすればよいですか? (ISynchronizeInvoke、Dispatcher、AsyncOperation、SynchronizationContext など)
まず、この質問にはwinformsやwpfなどの GUI 固有のタグが付けられていないことに注意してください。すぐにわかるように、これは意図的なものです。
第二に、この質問がやや長い場合は申し訳ありません。あちこちに散らばっているさまざまな情報を集めて、価値のある情報を提供するようにしています。ただし、私の質問は「知りたいこと」のすぐ下にあります。
私は最終的に、特定のスレッドでデリゲートを呼び出すために .NET によって提供されるさまざまな方法を理解することを使命としています。
私が知りたいこと:
特定のスレッドでデリゲートを呼び出すための最も一般的な方法 (Winforms または WPF 固有ではない) を探しています。
または、別の言い方をすると、これを行うためのさまざまな方法 (WPF
Dispatcher
を使用するなど) が相互に利用されているかどうか、およびその方法に興味があります。つまり、クロススレッド デリゲート呼び出しに共通のメカニズムが 1 つあり、それが他のすべてのメカニズムで使用されている場合です。
私がすでに知っていること:
このトピックに関連する多くのクラスがあります。その中で:
SynchronizationContext
(中System.Threading
)
私が推測しなければならないとしたら、それは最も基本的なものでしょう。正確に何をするのか、どのように使用されるのかはわかりませんが。AsyncOperation
& (in ) これらは のラッパーのようです。それらを使用する方法の手がかりはありません。AsyncOperationManager
System.ComponentModel
SynchronizationContext
WindowsFormsSynchronizationContext
(中System.Windows.Forms
)
のサブクラスSynchronizationContext
。ISynchronizeInvoke
(中System.ComponentModel
)
Windows フォームで使用されます。(Control
クラスはこれを実装しています。推測する必要がある場合、この実装は を利用していると思いますWindowsFormsSynchronizationContext
。)Dispatcher
& (in ) 後者は の別のサブクラスのようで、前者はそれに委譲されています。DispatcherSynchronizationContext
System.Windows.Threading
SynchronizationContext
一部のスレッドには、メッセージ キューと共に独自のメッセージ ループがあります。
(MSDN のページAbout Messages and Message Queuesには、メッセージ ループがシステム レベルでどのように機能するか、つまり Windows API としてのメッセージ キューに関する入門的な背景情報があります。)
メッセージ キューを使用してスレッドのクロススレッド呼び出しを実装する方法がわかります。
PostThreadMessage
Windows API を使用すると、デリゲートを呼び出す命令を含む特定のスレッドのメッセージ キューにメッセージを入れることができます。そのスレッドで実行されるメッセージ ループは最終的にそのメッセージに到達し、デリゲートが呼び出されます。MSDN で読んだことから、スレッドは自動的に独自のメッセージ キューを持ちません。メッセージキューは、スレッドがウィンドウを作成したときなどに利用可能になります。メッセージ キューがなければ、スレッドにメッセージ ループがあっても意味がありません。
では、ターゲット スレッドにメッセージ ループがない場合、クロススレッド デリゲート呼び出しはまったく可能でしょうか? たとえば、.NET コンソール アプリケーションではどうでしょうか。(この質問への回答から判断すると、コンソールアプリでは確かに不可能だと思います。)
wpf - WPF + タスク + WCF = SynchronizationContext がありませんか?
System.Threading.Tasks を使用してバックグラウンドで WCF サービスを呼び出す WPF アプリケーションがあります。Task.ContinueWith を使用して、サービス呼び出しの結果を WPF UI スレッドに返します。私の問題は、継続は UI スレッドで実行されますが、実行すると SynchronizationContext.Current が null になることです。最初のタスクで WCF 呼び出しをコメント アウトして、同じコードを実行できます。継続は UI スレッドで行われ、予想どおり DispatcherSynchronizationContext が使用されます。
WCF プロキシは ChannelFactory を使用して生成され、wsHttpBinding を使用します。コールバック コントラクトはありません。関連するコードを以下に示します。
このコードをそのまま実行すると、ServiceContinuation は正しいスレッド (ManagedThreadID を使用して検証) で呼び出されますが、SynchronizationContext.Current は null です。サービス呼び出し (result = service.TheServiceMethod();) を行う 1 行をコメント アウトすると、DispatcherSynchronizationContext を使用して ServiceContinuation が正しく呼び出されます。
1 つの注意点 - SynchronizationContext は永久に失われるわけではありません - ボタンをもう一度クリックすると、ボタン クリック ハンドラーには正しい SynchronizationContext があります。
2 つのケースのスタック トレースを取得しました。いくつかの違いがあります。同一の部分はすべて省略し、異なるスタックの一番上に加えて、参照用にいくつかのフレームのみを含めました。
失敗 - WCF サービスを呼び出します
成功 - WCF サービスへの呼び出しがありません
唯一の違いが WCF クライアント サービス呼び出し (コールバック コントラクトなし) である場合、メイン スレッドでの継続に SynchronizationContext がある場合とない場合がある理由を知っている人はいますか?
c# - SynchronizationContext と InvokeRequired
私はこの質問に対する答えを探していますが、満足のいく答えが見つからないようです。ここにいる誰かが私を啓発してくれるかもしれません。
UIスレッドで変更されたイベントを発生させるためにBindingList<T>
、オブジェクトへの参照を格納する子孫があります。SynchronizationContext
BindingList<T>
これが、バックグラウンド スレッドではなく UI スレッドで作成および使用された可能性もあります。私が利用できるようなプロパティなしでこれを確認するにはどうすればよいInvokeRequired
ですか? SynchronizationContext.Send
UI スレッドで呼び出した結果はどうなりますか?
c# - TaskScheduler.Current がデフォルトの TaskScheduler であるのはなぜですか?
Task Parallel Library は素晴らしく、私は過去数か月間よく使用してきました。ただし、本当に気になることがあります。それTaskScheduler.Current
は、デフォルトのタスク スケジューラであり、TaskScheduler.Default
. これは、ドキュメントやサンプルで一見しただけでは明らかではありません。
Current
別のタスク内にいるかどうかによって動作が変化するため、微妙なバグにつながる可能性があります。簡単には決められないもの。
.NET Framework で XxxAsync メソッドが行うのとまったく同じ方法で、イベントに基づく標準の非同期パターンを使用して、元の同期コンテキストで完了を通知する非同期メソッドのライブラリを作成しているとします (例: DownloadFileAsync
)。次のコードでこの動作を実装するのは非常に簡単なので、Task Parallel Library を実装に使用することにしました。
これまでのところ、すべてがうまく機能しています。それでは、WPF または WinForms アプリケーションでボタン クリック時にこのライブラリを呼び出してみましょう。
ここで、ライブラリ呼び出しを書いている人はTask
、操作が完了したときに新しい呼び出しを開始することを選択しました。珍しいことは何もありません。彼または彼女は、Web 上のどこにでもある例に従い、Task.Factory.StartNew
を指定せずに単純に使用TaskScheduler
します (2 番目のパラメーターで指定する簡単なオーバーロードはありません)。メソッドはDoSomethingElse
単独で呼び出されると正常に動作しますが、イベントによって呼び出されるとすぐにTaskFactory.Current
、ライブラリの継続から同期コンテキスト タスク スケジューラを再利用するため、UI がフリーズします。
特に 2 番目のタスク呼び出しが複雑な呼び出しスタックに埋もれている場合は、これを見つけるのに時間がかかることがあります。もちろん、すべてがどのように機能するかがわかれば、ここでの修正は簡単TaskScheduler.Default
です。スレッド プールで実行する予定のすべての操作を常に指定します。ただし、2 番目のタスクは別の外部ライブラリによって開始され、この動作を知らStartNew
ず、特定のスケジューラーなしで素朴に使用されている可能性があります。このケースはかなり一般的だと思います。
頭を悩ませた後、TPL を作成しているチームがデフォルトTaskScheduler.Current
の代わりに使用するという選択を理解できません。TaskScheduler.Default
- まったく明らかで
Default
はありません。デフォルトではありません! そして、ドキュメントは深刻に不足しています。 - によって使用される実際のタスク スケジューラ
Current
は、コール スタックに依存します。この動作で不変条件を維持するのは困難です。 - 最初にタスク作成オプションとキャンセル トークンを指定する必要があるため、タスク スケジューラを指定するのは面倒で
StartNew
、長い行が読みにくくなります。これは、拡張メソッドを作成するか、TaskFactory
を使用する を作成することで軽減できますDefault
。 - コール スタックをキャプチャすると、追加のパフォーマンス コストが発生します。
- タスクを実行中の別の親タスクに依存させたい場合は、コール スタック マジックに頼るのではなく、明示的に指定してコードを読みやすくすることを好みます。
この質問がかなり主観的に聞こえるかもしれませんが、なぜこのような振る舞いをするのかについて客観的な議論を見つけることができません。ここで何かが欠けていると確信しています。それが、私があなたに目を向けている理由です。
winforms - WinFormスレッドでWinForm同期コンテキストまたはスケジュールを取得する方法
私はwinformアプリケーションを持っており、次のような監視可能なセットアップがあります。
フォームを作成したメインスレッドでは実行されないため、これは機能しませんl => lb.Text = l.ToString()
が、このスレッドで実行する方法がわかりません。IObservable.SubscribeOn
どちらかIScheduler
を使用する必要があるとSynchronizationContext
思いますが、メインスレッドの同期コンテキストを取得する方法がわかりません。見つけたスケジューラーは、、、、、などの静的プロパティScheduler
のみScheduler.CurrentThread
でしImmediate
たNewThread
。どれもうまくいきませんでした。TaskPool
ThreadPool
私のRxバージョンは1.0.10621です。
c# - 使用可能なスレッドがなくなると、.ForEach ループ ブロックを実行します。
.ForEach
多くのタスクを開始するループ (TPL) があります。TPL はスレッド プールからスレッドを消費しているので、利用可能なスレッドがなくなったらどうなるのだろうか? スレッドが再び使用可能になるまで、呼び出し元のコードはブロックされますか?
Task
スレッドプールには、作業項目 ( ) がキューに入れられるグローバル作業キューがあることを知っています。そのキューがいっぱいになることはありますか?
私たちの問題は、一部のタスクは長時間 (30 分) 実行され、一部は短時間 (1 秒) 実行されることですが、そのようなタスクは数千にも上ります。TPL は、開始したタスクごとに新しいスレッドを開始しますか? ないと思います。スレッド プールはどの時点で使い果たされますか?
c# - TaskScheduler/SynchronizationContextを取得して特定のスレッドで実行する
WPFViewModelの次のコードを検討してください。
...ここで、modelChangedは、オブジェクトモデルの変更に応答するためのイベントハンドラーです。このコードはUIスレッドで実行され、発生元のスレッドに関係なく、UIスレッドでイベントが処理されることを期待して設計されています。
ただし、これを実行すると、出力は次のようになります。
私の期待は、スレッド1がすべての処理が行われる場所になることです。このようにSynchronizationContextを直接使用しようとしても:
...同じことがわかります。
私の考え方やアプローチに何か問題がありますか?initスレッドでイベントを処理するにはどうすればよいですか?
前もって感謝します!
c# - スレッドマーシャリングのようなフレームワーク
私は常に、SynchronizationContext を使用して別のスレッドへの呼び出しをマーシャリングできると考えていました。SyncCtx.Send() は指定されたデリゲートを呼び出す以外に何もしない (同じスレッドにとどまる) ため、どうやら私は間違っていたようです。SynchronizationContext から派生させて、スレッド コンテキストで作業する必要は本当にあるのでしょうか? 何かが足りない気がします。
達成したいこと: アプリ内でコマンドを実行するための小さな API を想像してみてください。コマンドの実行が終了したときに実行するデリゲートを割り当てることができるため、バックグラウンド スレッドでコマンドを実行することもできます。この "Call-me-when-done"-Delegate は、成功/失敗フラグ、オプションの例外情報などを含む 1 つのパラメーター (状態) を取得します。このデリゲートを元の呼び出しスレッドで呼び出して、lib を使用する開発者が必要な呼び出しなどを処理する必要があります。これを取り除いて、単純な非スレッド認識プログラミングを実行させたいと思います。WindowsFormsSynchronizationContext は、ターゲットとして何らかの制御を与えない限り、どちらも役に立たないようです。
助けてくれてありがとう!