Impossible (as I hate to use this word) transverse thread error?

Can someone explain how this can happen?

I am fully aware of thread-safe programming, and as you can see, I support UI updates through the InvokeRequired form, everything works fine here, and no changes to break it that I know, and now all of a sudden, the same way how do I program other parts of the application (perhaps added to this method in one step? I just can't remember) I am confusedly getting this error:

alt text

First, if InvokeRequired = true, this should mean BeginInvoke (), the [queued] method should be called again, and InvokeRequired should be false?

Should I not get this exception as it should be satisfied?

Hope to hear from several multithreading gurus :)

Graham

+6
multithreading
source share
5 answers

I suspect InvokedRevoked may be lying to you. WinForm Control cancels the creation of the control base Win32 HWND until a method call is needed. InvokeRequired will return false if the HWND has not yet been created.

For a detailed explanation, see "Mysterious Hangs or Big InvokeRequired Fraud"

If your background thread asks for InvokeRequired before the user interface thread causes Control to lazily create its HWND, InvokeRequired (incorrectly) tells your background thread that it doesn't need to use Invoke () to pass control back to the user interface thread, When the background thread then accesses the control, BAM! "InvalidOperationException: cross-thread operation is invalid!"

The user interface thread can manually force the control to create its own HWND handle so that Control.InvokeRequired will know that the user interface thread is the owner of the control:

Control control = new Control(); IntPtr handle = control.Handle; // if you ask for HWND, it will be created 
+9
source share

Most people see this error and see one thing: "you are not accessing this control from the main user interface thread." In fact, you can have 100 UI threads if you want (the behavior for this is undefined, but supported). Most likely, panelMain is created on another thread (this); I do not see the code - but it looks like you are creating it in your worker / thread.

To confirm the behavior, try the following:

 Action addAction = new Action ( new delegate { panelMain.Controls.Add(UCLoadingScreen); } ) if(panelMain.InvokeRequired) { panelMain.Invoke(addAction); // Breakpoint here. } else { addAction(); } 

Be prepared for another error (a child control in another thread is parent for it, not sure which error you will get, but I'm sure you will). It's not a problem.

A factory will fix this:

 public void CreateControl<T>() where T : new() { if(InvokeRequired) { return (T)Invoke(new Func<T>(CreateControl<T>())); } return new T(); } 

EDIT: panelMain may not be the "intruder" of the thread, as I said, parental controls from different threads lead to undefined behavior. Ensure that all controls are created in the context of the main thread.

+5
source share

There is no such thing as an impossible transverse thread error!

0
source share

Hope this works for you. I assume your gui stuff is in the same thread. Just initialize this singleton and rely on it whenever you want to call the Control.InvokeRequired property.

Greetings

Greg

 public sealed class UiThread { #region Singleton // Singleton pattern implementation taken from Jon Skeet C# and .NET article www.yoda.arachsys.com/csharp/singleton.html UiThread() { } public static UiThread Instance { get { return Nested.instance; } } class Nested { // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit static Nested() { } internal static readonly UiThread instance = new UiThread(); } #endregion int _uiThreadId = 0; public void SetUiThread(Thread thread) { if (_uiThreadId != 0) throw new ApplicationException("UI Thread has already been established!"); if (thread.ManagedThreadId == 0) throw new ArgumentException("Unexpected thread id value of 0!"); if (thread.IsBackground) throw new ArgumentException("Supplied thread should not be a background thread!"); if (thread.IsThreadPoolThread) throw new ArgumentException("Supplied thread should not be a thread pool thread!"); _uiThreadId = thread.ManagedThreadId; } /// <summary> /// It possible for InvokeRequired to return false when running in background thread. /// This happens when unmanaged control handle has not yet been created. /// We second-guess Microsoft implementation in this case, checking against foreground thread Id. /// </summary> /// <param name="control">Control to check against.</param> public bool InvokeRequired(Control control) { if (control.InvokeRequired) return true; IntPtr unmanagedHandle = control.Handle; bool newResult = control.InvokeRequired; if (unmanagedHandle == IntPtr.Zero) { // Trace.WriteLine() call here forces unmanagedHandle initialization, // even with optimizing compiler. Trace.WriteLine(string.Format("Control handle could not be established! Control was {0}.", control.ToString())); } bool retVal = InvokeRequired(); // Break whenever the result of our check does not match theirs. Debug.Assert(retVal == newResult); // Return our InvokeRequired result over theirs // to keep with the tradition of updating controls from foreground only. return retVal; } /// <summary> /// Prefer to use overload with Control argument if at all possible. /// It possible for InvokeRequired to return false when running in background thread. /// This happens when unmanaged control handle has not yet been created. /// We second-guess Microsoft implementation in this case, checking against foreground thread Id. /// </summary> public bool InvokeRequired() { if (_uiThreadId == 0) throw new ApplicationException("UI Thread has not been established!"); return (Thread.CurrentThread.ManagedThreadId != _uiThreadId); } 

}

0
source share

Use

 if (InvokeRequired) { //invoke } else { //do } 
-one
source share

All Articles