插座/线程问题:撤消操作遇到一个方面是从什么在相应的设置操作应用于不同操作、是从、应用于、线程

2023-09-04 00:53:10 作者:魂淡

我有问题,上述多问,有关错误。我们有一个TCP / IP服务器应用程序,它一直在努力罚款多年。我现在需要允许应用程序接受来自直接连接的USB设备连接,通过在内部使用的套接字连接通过打补丁到本地主机(127.0.0.1)服务器应用程序中。 (顺便说一句我提到的USB只解释为什么我这样做 - 我禁用所有的USB功能调试这个问题的一部分)。

沿该套接字的通信可以导致调用客户端和服务器端上的GUI元素。访问GUI客户端上的内容引起标题错误(调用堆栈如下图)。这里的一个关键问题是,调试器无法停止的例外:尽管所有的异常被设置为暂停时抛出的应用程序只是终止时发生错误

这似乎是唯一对我的应用程序的唯一的事情是,它使用一个内部接口连接到127.0.0.1。我还证实,该应用程序工作正常,如果客户端被分离成单独的应用程序。但是,我不能以此作为其他原因长久之计。

有几个帖子讨论这样的问题,我在下面列出。不幸的是似乎没有提供在我的情况的解决方案:

在大多数相关帖子讨论是否需要确保所有的GUI操作GUI线程上执行,通过调用或BeginInvoke。我相信我的应用程序正确地做到这一点(它获得的一种形式使用Application.Forms获得的主要形式,并在此呼吁调用),并在调试器有双重检查。 有关上述情况,有一些讨论,以便阻止/不阻止使用调用的VS的BeginInvoke。就我而言都具有相同的结果。 在一些帖子建议,有必要在GUI线程(我是)上创建插座本身。 This 之一解释说,如果你在你的应用程序(我不知道)使用的DoEvents可以得到错误。 This 之一也意味着你可以用一个缺少EndConnect呼叫使用客户端套接字连接(我的客户端连接是同步)异步调用时出现错误。 This 之一解释说,你可以从InvokeRequired得到不正确的结果,如果还没有创建的窗口句柄(已检查过本与IsHandleCreated)。 This一个在微软连接报告了类似的冠冕堂皇的错误,但不必须的解决方案(微软一直在研究它,因为2006年!) This 之一包含了一个建议,使用AsyncOperationManager.SynchronizationContext备份/恢复sync​​hronsiation方面,它(意料之中?)只是导致不同的错误。 有几个帖子说表明,误差仅为调试和下面就让它消失 - 但我没有打扰试图说: System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls = FALSE JAVA面试专题二 线程

有其他帖子问类似的问题:here, here和here.一个很好的here了。

下面是一个code片段 - 这将导致在ProcessCommandCT崩溃时,客户端收到套接字数据:

 查找任何线程应用程序的主要形式
有只有一个实例RibbonForm1',这是主要的形式
公共功能GetRibbonForm()作为RibbonForm1
    昏暗的RF作为RibbonForm1 =无
    对于每个F作为形成My.Application.OpenForms
        RF = TryCast(F,RibbonForm1)
        如果RF状态并没有任何再返回射频
    下一个
    返回任何结果
端功能

公用Sub ProcessCommandCT(CMD BYVAL作为字符串)
    code穿插着这些调试此问题
    Debug.Assert的(GetRibbonForm.IsHandleCreated)
    Debug.Assert的(不GetRibbonForm.InvokeRequired)
    尝试
        选择案例CMD
            案MYCMD
                昏暗˚F作为新形式
                f.ShowDialog()
        最终选择
    抓住EX为例外
        MSGBOX(ex.ToString)
    结束尝试

结束小组

私人小组sock_Receive(MSG BYVAL作为字符串)处理sck.Receive
    昏暗的RF作为RibbonForm1 = GetRibbonForm
    如果rf.InvokeRequired然后
        rf.BeginInvoke(新SubWith​​StringArgDelegate(AddressOf ProcessCommandCT),新对象(){}味精)
    其他
        ProcessCommandCT(MSG)
    结束如果
结束小组
 

我使用VB .NET 2010 .NET4。

感谢您的帮助 - 我希望职位的综合列表上方还可以帮助别人

调用堆栈:

 线程<没有名称> (0x148c)已退出与code 0(为0x0)。
System.Transactions的关键:0:其中,TraceRecord的xmlns =htt​​p://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord Severity="Critical"><TraceIdentifier>http://msdn.microsoft.com/Trace$c$cs/System/ActivityTracing/2004/07/Reliability/Exception/Unhandled</TraceIdentifier><Description>Unhandled exception</Description><AppDomain>myapp.vshost.exe</AppDomain><Exception><ExceptionType>System.InvalidOperationException, mscorlib程序,版本= 4.0.0.0,文化=中性公钥= b77a5c561934e089&LT; / ExceptionType&GT;&LT;消息&gt;将撤消操作遇到一个方面是从什么在相应的设置操作应用于不同。可能的原因是,上下文设置线程上,而不是回复(撤消)&LT; /消息&GT;&LT;堆栈跟踪&GT;在System.Threading.SynchronizationContextSwitcher.Undo()
在System.Threading.ExecutionContextSwitcher.Undo()
在System.Threading.ExecutionContext.runFinally code(用户数据对象,布尔exceptionThrown)
在System.Runtime.CompilerServices.RuntimeHelpers.ExecuteBackout codeHelper(对象搁置code,对象用户数据,布尔exceptionThrown)
在System.Runtime.CompilerServices.RuntimeHelpers.Execute codeWithGuaranteedCleanup(试行code code,清理code撤销code,对象USERDATA)
在System.Threading.ExecutionContext.RunInternal(ExecutionContext中的ExecutionContext,ContextCallback回调,对象的状态)
在System.Threading.ExecutionContext.Run(ExecutionContext中的ExecutionContext,ContextCallback回调,对象的状态,布尔ignoreSyncCtx)
在System.Threading.ExecutionContext.Run(ExecutionContext中的ExecutionContext,ContextCallback回调,对象的状态)
在System.Net.ContextAwareResult.Complete(IntPtr的userToken)
在System.Net.LazyAsyncResult.ProtectedInvokeCallback(对象结果,IntPtr的userToken)
在System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32的错误code,UInt32的的numBytes,NativeOverlapped * nativeOverlapped)
在System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32的错误code,UInt32的的numBytes,NativeOverlapped * pOVERLAP)&LT; /堆栈跟踪&GT;&LT; ExceptionString&GT; System.InvalidOperationException:撤消操作遇到一个方面是从什么样的应用于不同相应的设置操作。可能的原因是,上下文设置线程上,而不是回复(撤消)。
在System.Threading.SynchronizationContextSwitcher.Undo()
在System.Threading.ExecutionContextSwitcher.Undo()
在System.Threading.ExecutionContext.runFinally code(用户数据对象,布尔exceptionThrown)
在System.Runtime.CompilerServices.RuntimeHelpers.ExecuteBackout codeHelper(对象搁置code,对象用户数据,布尔exceptionThrown)
在System.Runtime.CompilerServices.RuntimeHelpers.Execute codeWithGuaranteedCleanup(试行code code,清理code撤销code,对象USERDATA)
在System.Threading.ExecutionContext.RunInternal(ExecutionContext中的ExecutionContext,ContextCallback回调,对象的状态)
在System.Threading.ExecutionContext.Run(ExecutionContext中的ExecutionContext,ContextCallback回调,对象的状态,布尔ignoreSyncCtx)
在System.Threading.ExecutionContext.Run(ExecutionContext中的ExecutionContext,ContextCallback回调,对象的状态)
在System.Net.ContextAwareResult.Complete(IntPtr的userToken)
在System.Net.LazyAsyncResult.ProtectedInvokeCallback(对象结果,IntPtr的userToken)
在System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32的错误code,UInt32的的numBytes,NativeOverlapped * nativeOverlapped)
在System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32的错误code,UInt32的的numBytes,NativeOverlapped * pOVERLAP)&LT; / ExceptionString&GT;&LT; /异常&GT;&LT; / TraceRecord&GT;
该方案[6324] myapp.vshost.exe:托管(v4.0.30319)已退出与code 0(为0x0)。
 

解决方案

这异常当一个线程的执行上下文属性更改发生。特别是当线程是一个线程池或I / O完成线程执行回调,并从取得了的BeginXXX调用启动异步操作另一个线程获取了它的ExecutionContext。像Socket.BeginReceive()。

有足够的要做到这一点,在贴code,因为它与形式的回调锅匠们的机会。 ExecutionContext中有一个名为SynchronizationContext的隐藏属性,它跟踪SynchronizationContext.Current的。的WinForms安装了一个自定义同步提供程序创建的任何形式的第一次。要求正确元帅从工作线程UI线程调用。距离的SynchronizationContext派生的类名为WindowsFormsSynchronizationContext。

因此​​,可能的故障模式是,sock_Receive()方法被调用的在的创建任何的WinForms形式。用c安装同步提供者和改变执行上下文,因此轰然code除外表单创建$ C $。这样的问题需要加以固定通过改变应用程序的初始化,确保主要存在形式,然后再允许任何异步code使用的BeginInvoke()。

I'm having problems with the above much asked-about error. We have a TCP/IP server application which has been working fine for some years. I now need to allow the application to accept connections from directly connected USB devices, by internally using a socket connection to patch through to localhost (127.0.0.1) within the server application. (BTW I mention the USB only to explain why I am doing this - I disabled all USB functions as part of debugging this problem).

The communications along this socket can result in calls to GUI elements on both the client and the server side. Accesses to GUI elements on the client side cause the error in the title (call stack below). One of the key problems here is that the debugger is unable to halt on the exception: despite all exceptions being set to halt when thrown the application simply terminates when the error occurs.

The only thing that seems unique about my application is that it uses an internal socket to connect to 127.0.0.1. I have also confirmed that the application works fine if the client is separated into a separate application. However, I can't use this as a permanent solution for other reasons.

There are several posts discussing this sort of problem which I have listed below. Unfortunately none seem to provide a solution in my case:

Most related posts discuss the need to ensure that all GUI operations are performed on the GUI thread, by using Invoke or BeginInvoke. I am confident my application does this correctly (it obtains a form using Application.Forms to get the main form and calls Invoke on this) and have double checked in the debugger. Relating to the above, there is some discussion as to the use of Invoke vs BeginInvoke in order to block/not block. In my case both have the same result. Some posts suggest it is necessary to create the sockets themselves on the GUI thread (mine are). This one explains that you can get the error if you use DoEvents in your application (I don't). This one also implies that you could get the error with a missing EndConnect call when using asynchronous calls for client socket connection (my client connection is synchronous). This one explains that you can get incorrect results from InvokeRequired if the window handle is not yet created (have checked this with IsHandleCreated). This one on microsoft connect reports a similar sounding bug but doesnt have a solution (microsoft have been 'investigating' it since 2006!) This one contains a suggestion to use AsyncOperationManager.SynchronizationContext to backup/restore the synchronsiation context, which (unsurprisingly?) just causes different errors. There are a couple of posts that suggest that the error is debug only, and the following will make it go away - but I haven't bothered trying that: System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls = false

There are other posts asking similar questions: here, here and here. A good one here too.

Here is a code snippet - this causes a crash within ProcessCommandCT when socket data is received by the client:

' Find application main form from any thread
' There is only one instance of 'RibbonForm1' and this is the main form
Public Function GetRibbonForm() As RibbonForm1
    Dim rf As RibbonForm1 = Nothing
    For Each f As Form In My.Application.OpenForms
        rf = TryCast(f, RibbonForm1)
        If rf IsNot Nothing Then Return rf
    Next
    Return Nothing
End Function

Public Sub ProcessCommandCT(ByVal cmd As String)
    ' code is peppered with these to debug this problem
    Debug.Assert(GetRibbonForm.IsHandleCreated)
    Debug.Assert(Not GetRibbonForm.InvokeRequired)
    Try
        Select Case cmd
            Case "MYCMD"
                Dim f As New Form 
                f.ShowDialog()
        End Select
    Catch ex As Exception
        MsgBox(ex.ToString)
    End Try

End Sub

Private Sub sock_Receive(ByVal msg As String) Handles sck.Receive
    Dim rf As RibbonForm1 = GetRibbonForm
    If rf.InvokeRequired Then
        rf.BeginInvoke(New SubWithStringArgDelegate(AddressOf ProcessCommandCT), New Object() {msg})
    Else
        ProcessCommandCT(msg)
    End If
End Sub

I'm using VB .NET 2010 with .NET4.

Thanks for any help - I hope the consolidated list of posts above also helps others.

Tim

Call stack:

The thread '<No Name>' (0x148c) has exited with code 0 (0x0).
System.Transactions Critical: 0 : <TraceRecord    xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Critical"><TraceIdentifier>http://msdn.microsoft.com/TraceCodes/System/ActivityTracing/2004/07/Reliability/Exception/Unhandled</TraceIdentifier><Description>Unhandled exception</Description><AppDomain>myapp.vshost.exe</AppDomain><Exception><ExceptionType>System.InvalidOperationException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>The Undo operation encountered a context that is different from what was applied in the corresponding Set operation. The possible cause is that a context was Set on the thread and not reverted(undone).</Message><StackTrace>   at System.Threading.SynchronizationContextSwitcher.Undo()
at System.Threading.ExecutionContextSwitcher.Undo()
at System.Threading.ExecutionContext.runFinallyCode(Object userData, Boolean exceptionThrown)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteBackoutCodeHelper(Object backoutCode, Object userData, Boolean exceptionThrown)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.ContextAwareResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)</StackTrace><ExceptionString>System.InvalidOperationException: The Undo operation encountered a context that is different from what was applied in the corresponding Set operation. The possible cause is that a context was Set on the thread and not reverted(undone).
at System.Threading.SynchronizationContextSwitcher.Undo()
at System.Threading.ExecutionContextSwitcher.Undo()
at System.Threading.ExecutionContext.runFinallyCode(Object userData, Boolean exceptionThrown)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteBackoutCodeHelper(Object backoutCode, Object userData, Boolean exceptionThrown)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.ContextAwareResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)</ExceptionString></Exception></TraceRecord>
The program '[6324] myapp.vshost.exe: Managed (v4.0.30319)' has exited with code 0 (0x0).

解决方案

This exception occurs when a thread's ExecutionContext property changes. Specifically when that thread is a threadpool or I/O completion thread that executes a callback and it acquired its ExecutionContext from another thread that made a BeginXxx call to start an asynchronous operation. Like Socket.BeginReceive().

There's ample of opportunity for this to happen in the posted code since it tinkers with forms in the callback. ExecutionContext has a hidden property named SynchronizationContext which keeps track of SynchronizationContext.Current. Winforms installs a custom synchronization provider the first time any form is created. Required to properly marshal calls from a worker thread to the UI thread. It is a class derived from SynchronizationContext named WindowsFormsSynchronizationContext.

The likely failure mode therefore is that the sock_Receive() method is called before any Winforms forms are created. With the form creation code installing the synchronization provider and altering the ExecutionContext and thus crashing the code with the exception. Such a problem needs to be fixed by altering the initialization of the app, ensuring that a main form exists before you allow any asynchronous code to use BeginInvoke().