INVOKEREQUIREDを使用していても、クロススレッド操作は無効です[重複] -- c# フィールド と winforms フィールド と .net-4.0 フィールド と thread-safety フィールド と multithreading フィールド 関連 問題

Cross-thread operation not valid, even if using InvokeRequired [duplicate]












6
vote

問題

日本語

私はそれに私のカスタムコントロールを持つフォームを持っています。

私の形式の方法を持っています:

<事前> <コード> private void SetEnabledOnControls(bool val) { if (InvokeRequired) { Invoke((Action<bool>)SetEnabledOnControls, val); } else { //do the work - iterate over child controls, //and they iterate over their children, etc... } }

および<コード> else ブランチにあるメソッド内部は、上記の例外を取得します。
<コード> Cross-thread operation not valid: Control 'txtNumber' accessed from a thread other than the thread it was created on.

私のシナリオは実際にはもう少し複雑です - 私はこれを例として推定したばかりです。実際に起こっているのは、WorkFlowFoundationを使用しているということです.InklowApplication(ConflowApplication(ConflowApplication(ConflowApplication)が実行されています(それはそれ自身のスレッドで実行します)、それがイベントを購読し、そこから SetEnabledOnControls 。また、私はブックマークを使ってワークフローを再開しています(そしてまた、シナリオには関与していません)。

InvokeRequiredの私の明白な誤解とは無関係です - InvokeRequiredがfalseの場合、私はクロススレッド例外がありますか?私はコントロールの「手動」を作成しません - それはDesignerによって配置されたInitialize()にあります。

誰もがこれにいくつかの光を当てることができますか?

ありがとう!

編集 Gwllosaの提案を使用して、 System.Threading.Thread.CurrentThread.ManagedThreadId を使用してthreadidを追跡しました。今すぐWeirdの部分が来る... Initialize()のスレッドIDは10です。最初の2つの状態を渡すと、ID 13 - InvokeRequiredが正しく呼び出されました。しかし、2番目の状態の後、<コード> SetEnabledOnControls に入ると、もう一度13がありますが、今回はInvokeRequiredが偽です。どうして!?後で、もちろん、子どものコントロールを変更できません(驚くべきことではありません)。どういうわけか、それが住んでいるスレッドを変更したのは??

編集2 今私は存在しています:

<事前> <コード> if (IsHandleCreated) { Invoke((Action<bool>)SetEnabledOnControls, val); }

と<コード> IsHandleCreated はtrueですが、それでもdevspeed window-handle-has-b">

編集3 FacePalm :)状態を再開していたボタンの1つは、フォームの最初のCancelButtonでした。そのようにプロパティから削除されたとき、CodeBihIndはそれに依然としてDialogresult = Cancelを持っていました - 私のフォームは確かに終了していました、そしてもちろん、それはエラーが正しい情報を返しませんでした。 。

みんなありがとう!今日の新しいことを学びました:)

英語

I have a form with my custom controls on it.

I have a method in my Form:

private void SetEnabledOnControls(bool val) {   if (InvokeRequired)   {       Invoke((Action<bool>)SetEnabledOnControls, val);   }   else   {        //do the work - iterate over child controls,         //and they iterate over their children, etc...   } } 

And inside the methods that are on the else branch I get the mentioned exception:
Cross-thread operation not valid: Control 'txtNumber' accessed from a thread other than the thread it was created on.

My scenario is actually a bit more complicated - I just extrapolated this as an example. What's actually going on is that I'm using WorkflowFoundation - I have StateMachineActivity (CTP1) running in WorkflowApplication (which runs in it's own thread), I subscribed to it's event, and from there I'm calling SetEnabledOnControls. Also, I'm using bookmarks to resume my workflow (and also, there's MEF on the side, not involved in the scenario).

All of that is irrelevant to my obvious misunderstanding of the InvokeRequired - how is it possible that if the InvokeRequired is false, I have cross threaded exception? I don't create any of the controls 'manually' - it's all there in the Initialize() placed by designer.

Can anyone shed some light on this?

Thanks!

EDIT Using GWLlosa suggestion, I've tracked the ThreadId using System.Threading.Thread.CurrentThread.ManagedThreadId. Now comes the weird part... the thread id in Initialize() is 10. Between passing the first 2 states, it comes in with Id 13 - InvokeRequired was true, and it invoked correctly. BUT, after the second state, when it enters SetEnabledOnControls it's again 13, but this time InvokeRequired is false! How come!? Later on, of course, it fails to change child controls (not surprising). Could it be that the Form somehow changed the thread it's living in??

EDIT 2 Now I'm calling with:

 if (IsHandleCreated)  {      Invoke((Action<bool>)SetEnabledOnControls, val);  } 

and it has IsHandleCreated to true, but still fails with what devSpeed pointed at.

EDIT 3 FACEPALM :) One of the buttons that were resuming state was at first CancelButton for the Form. When it was removed from the property as such, the codebihind still had the DialogResult=Cancel for it - so my form was indeed closing, and of course it was missing the handle so the InvokeRequired didn't return correct info, and hence the errors.

Thanks everyone! I learned a new thing today :)

</div
              

回答リスト

2
 
vote

コントロールが作成されたときに(initialize()関数)とそれをタッチしようとする直前にスレッドIDを記録した場合は、デバッグが簡単になる可能性があります。一般的に、私はあなたが最初に期待しているもの以外のスレッドのコントロールを起こしたときにこれが起こったのを見ました。

 

It might make your debugging easier if you log the thread ID when the controls are created (in the Initialize() function) and the thread ID just before you try to touch it. Generally, I've seen this happen when you've somehow created the controls on a thread other than the one you expect in the first place.

</div
 
 
 
 
0
 
vote

私はちょうど私自身の問題を解消してから、FlowLayoutPanel内で動的にコントロールを作成するという問題を持っています。

<事前> <コード> public static void RenderEditorInstance(DataContext dataContext, object selectedItem, Form targetForm, Control targetControl, List<DynamicUserInterface.EditorControl> editorControls, EventHandler ComboBox_SelectedIndexChanged, EventHandler TextBoxControl_TextChanged, EventHandler CheckBox_CheckChanged, EventHandler NumericUpDown_ValueChanged, CheckedListControl.ItemChecked OnItemChecked, EventHandler dateTimePicker_ValueChanged, DynamicUserInterface.DuplicationValidationFailed liveLookupValidationFailed, DynamicUserInterface.PopulateComboBoxCallback populateComboBoxCallback) { if (targetForm.InvokeRequired) { InstanceRenderer renderer = new InstanceRenderer(RenderEditorInstance); targetForm.Invoke(renderer, dataContext, selectedItem, targetForm, targetControl, editorControls, ComboBox_SelectedIndexChanged, TextBoxControl_TextChanged, CheckBox_CheckChanged, NumericUpDown_ValueChanged, OnItemChecked, dateTimePicker_ValueChanged, liveLookupValidationFailed, populateComboBoxCallback); } else { targetControl.Padding = new Padding(2); targetControl.Controls.Clear(); ...{other code doing stuff here } } }

と約12の1つでは、このコードが使用されていた場合、クロススレッド例外が発生していました。このコードが使用されていた場所のすべてのインスタンスは、そのような方法で書かれていました。インターフェイスビルディングは、「await」キーワードを使用して非同期的に達成されます。

Gwllosaによって行われた提案を使用して、私は所有の範囲を取得するために制御するための拡張方法を書いた。

<事前> <コード> public static Thread OwnerThread(this Control ctrl) { Thread activeThread = null; if (ctrl.InvokeRequired) { activeThread = (Thread)ctrl.Invoke(new Func<Control, Thread>(OwnerThread), new object[] { ctrl }); } else { activeThread = Thread.CurrentThread; } return activeThread; }

..これは、少数の反復後にスレッドIDが確かに変化していたことを強調しました。

このコードのいくつかの奥深くにあるこのコードのいくつかは、MSDNからのTASK.RUN()を使用して、関連するコントロールのデータを取り出すために使用されるルーチン( https://msdn.microsoft.com/en-us/library/hh195051(v = vs.110).aspx )は明らかに:

例は非同期タスクが別の上で実行されることを示しています メインアプリケーションスレッドよりスレッド

TASK.RUN()が方程式から取り出されると、コントロールのスレッドは変更されません。だからあなたはそれを使うのにどのようにそしていつ使うのかについて注意する必要があります!

 

I just ran into a similar problem myself, where I have a function tearing down, and then dynamically creating controls within a FlowLayoutPanel:

        public static void RenderEditorInstance(DataContext dataContext, object selectedItem, Form targetForm, Control targetControl, List<DynamicUserInterface.EditorControl> editorControls, EventHandler ComboBox_SelectedIndexChanged, EventHandler TextBoxControl_TextChanged, EventHandler CheckBox_CheckChanged, EventHandler NumericUpDown_ValueChanged, CheckedListControl.ItemChecked OnItemChecked, EventHandler dateTimePicker_ValueChanged, DynamicUserInterface.DuplicationValidationFailed liveLookupValidationFailed, DynamicUserInterface.PopulateComboBoxCallback populateComboBoxCallback)         {           if (targetForm.InvokeRequired)             {                 InstanceRenderer renderer = new InstanceRenderer(RenderEditorInstance);                 targetForm.Invoke(renderer, dataContext, selectedItem, targetForm, targetControl, editorControls, ComboBox_SelectedIndexChanged, TextBoxControl_TextChanged, CheckBox_CheckChanged, NumericUpDown_ValueChanged, OnItemChecked, dateTimePicker_ValueChanged, liveLookupValidationFailed, populateComboBoxCallback);             }             else             {                 targetControl.Padding = new Padding(2);                 targetControl.Controls.Clear();                  ...{other code doing stuff here }             }          } 

And in one instance of about 12 where this code was being used, a cross-thread exception was being raised. All instances of where this code was being used, was written in such a way, that the interface building is achieved asynchronously using the 'await' keyword.

Using the suggestion made by GWLlosa, I wrote an extension method to controls to get the OwningThread a control belongs to:

    public static Thread OwnerThread(this Control ctrl)     {         Thread activeThread = null;          if (ctrl.InvokeRequired)         {             activeThread = (Thread)ctrl.Invoke(new Func<Control, Thread>(OwnerThread), new object[] { ctrl });         }         else         {             activeThread = Thread.CurrentThread;         }          return activeThread;     } 

..which highlighted that after a few iterations the Thread Id was indeed changing.

Buried deep inside some of this code were routines used to fetch data populating the relevant controls, through the use of Task.Run() which from MSDN (https://msdn.microsoft.com/en-us/library/hh195051(v=vs.110).aspx) clearly states:

The example shows that the asynchronous task executes on a different thread than the main application thread

Once the Task.Run() was taken out of the equation, the control's thread never changed. So you need be careful about how and when you use it!

</div
 
 

関連する質問

4  QTはバックグラウンドで作業するためにQTを作成しますか?  ( How many threads does qt create to work in the background ) 
QTをロットに使います。私は何かを知りたいのです:Qtは何のスレッドを作成しますか?シグナルやスロットを取り扱うのと同じように。 また、GUI Toolkitもイベントスレッドを作成します(Javaは覚えています)。 QTも作成しますか? 編集:「スレッド数...

4  Delphi Win API CreateTimerQueuetimerスレッドとスレッドセーフフォーマットDateTimeクラッシュ  ( Delphi win api createtimerqueuetimer threads and thread safe formatdatetime cras ) 
これは長い質問ですが、ここで行く。 を使用するという点でスレッドセーフであると言われるFormatDateTimeのバージョンがあります。 <事前> <コード> GetLocaleFormatSettings(3081, FormatSettings); ...

127  C#でスレッドプールを使用するときは? [閉まっている]  ( When to use thread pool in c ) 
閉鎖。この質問は意見ベースです。現在答えを受け付けていません。 この質問を改善したいですか? ...

5  なぜ.exeは止まるのを拒否しますか?  ( Why does exe refuse to stop ) 
デバッグしなければならない従来のC#/ C ++プログラムを「継承」しました。現在の問題は、プログラムを閉じた後に.exeが停止しないことです。これはまだタスクマネージャに表示されます。 これは問題であるため、インスタンスが1つだけ実行できるため、プログラムを...

1  私のメソッドがスレッドセーフかどうかにかかわらず、いつ自分で尋ねるべきですか?  ( When should i ask myself if my method is thread safe or not ) 
私のメソッドがスレッドセーフかどうかを考慮に入れるべきですか? ありがとう。 ...

64  Win32の下でのヒープ破損。見つける方法  ( Heap corruption under win32 how to locate ) 
ヒープを破損しているマルチスレッド c ++アプリケーションに取り組んでいます。この汚職を見つけるための通常のツールは不可能なようです。ソースコードの古いビルド(18ヶ月)は、最新のリリースと同じ動作を示しているので、これは長い間歩き回っており、ちょうど注目さ...

1  C#タイマー/イベントレース - タイマースレッドをフラッシュする  ( C sharp timer event race flushing the timers thread ) 
私は、コールバックがSystem.timers.Timerスレッドで実行されないようにすることができる方法を探しています。 基本的に私はタイマーと非同期ソケットを持っています - 時間が経過したとき、または新しいパケットが受信されたときに適切な関数を呼び出すこ...

606  クロススレッド操作が無効:それが作成されたスレッド以外のスレッドからアクセスされたコントロール  ( Cross thread operation not valid control accessed from a thread other than the ) 
シナリオがあります。 (Windows Forms、C#、.NET) 何らかのユーザーコントロールをホストする主なフォームがあります。 ユーザーコントロールは、 UserControl_Load メソッドを直接呼び出すと、UIがロードメソッドの実行の間に無応...

15  どのように多くのスレッド私は私のJavaプログラムで使用する必要がありますか?  ( How many threads should i use in my java program ) 
私は最近、大規模なデータベースから情報を取得し、いくつかの処理を行い、情報に関する詳細な画像を生成し、小さなJavaプログラムを継承しました。原作者は、単一スレッドを使用してコードを書いて、その後、それは複数のスレッドを使用できるようにそれを修正しました。 ...

8  スレッドをプロセッサにバインドします  ( Bind threads to processors ) 
マルチスレッドコードを実行すると、システム(Linux)はスレッドをあるプロセッサから別のプロセッサに移動します。プロセッサがあるのと同じくらい多くのスレッドを持っているので、それは良い理由ではなくキャッシュを無効にして、トレース活動を混乱させる。 スレッド...




© 2022 cndgn.com All Rights Reserved. Q&Aハウス 全著作権所有