为什么单独的线程会导致我的UI冻结?

时间:2018-01-28 17:17:47

标签: vb.net multithreading freeze

我在Windows窗体应用程序中启动一个线程,尝试连接到服务器并从该服务器检索信息。

与此同时,我希望我的用户仍能正常使用他的用户界面。

但显然事实并非如此。如果我无法连接到服务器,则在尝试超时前花费大约40秒,同时,我的UI仍然处于冻结状态。

请注意,我的UI流程的代码仍然运行。我仍然可以达到线程启动后发生的断点。

线程就像这样开始:

Public Sub NextRecord()
    Dim myThread As Thread
    myThread = New Thread(AddressOf ReadRecord)
    myThread.Start()
End Sub

我100%确定它冻结了UI而不是其他逻辑的线程,因为如果我注释掉对NextRecord的调用,应用程序运行没有问题。

什么可能导致线程阻止UI正常运行?我该怎么调试呢?我现在一直想弄清楚这一整天,我有点绝望。

编辑: 尝试过互锁的东西,但这不是问题

Edit2:以下是我认为可能相关的代码的一些部分

首先,我的" ReadRecord"方法。它的目标是找到一个可从服务器列表中访问的服务器,并尝试读取有效的数据行

'Reads a PLC record from the next available server in the list and updates the current server
Sub ReadRecord()

    ' If current state is busy then exit
    ' If 1 = Interlocked.Exchange(busy, 1) Then
    If busy = 1 Then
        Debug.Write("Trying to read, but another thread is already reading")
        Exit Sub
    End If
    'Interlocked.Exchange(busy, 0)
    busy = 1
    ' look for the first server with connected status
    For i = 0 To serverList.Count - 1
        Dim newIndex = (currentIndex + 1) Mod serverList.Count
        ' Interlocked.Exchange(currentIndex, newIndex) 
        currentIndex = newIndex
        Dim daServer As ADSServer = GetCurrentServer()
        ' Check the server status
        If GetAndUpdateServerStatus(daServer) Then '<----- this is where the freeze comes
            ' Check if the server is in tempo
            If daServer.IsInTempo() Then
                ' We can read from that server
                Dim record As PLCRecord
                record = daServer.ReadPLCRecord(tcads)
                If record.IsValid() Then
                    ' Stop the loop, because we read a valid record
                    Exit For
                End If
            End If
        End If
    Next
    'Release the lock
    ' Interlocked.Exchange(busy, 0)
    busy = 0
End Sub

对GetAndUpdateServerStatus的调用尝试连接到服务器并更新其&#34; alive&#34;状态

该方法进行了一些变量检查,并最终调用以下方法:

    Function OpenADSConnection(tcads As AxADSOCXLib.AxAdsOcx, Optional ByRef exception As String = "", Optional serverId As String = "", Optional port As String = "") As Boolean

    'first, make sure that we're not interfering with another connection
    If tcads.AdsAmsConnected Then
        exception = "OpenADSConnection - Connexion ADS déjà ouverte pour " & tcads.AdsAmsServerNetId & " Impossible d'ouvrir une nouvelle connexion pour " & serverId & " tant que la connexion n'est pas fermée."
        Return False
    End If

    tcads.AdsAmsServerNetId = IIf(serverId = "", My.Settings.adsServerId, serverId)
    tcads.AdsAmsServerPort = IIf(port = "", My.Settings.adsPort, port)
    tcads.AdsAmsConnect() '<---- this is an API call to connect to the server. tcads is an activeX control using microsoft COM (according to their doc) 

    If Not tcads.AdsAmsConnected Then
        exception = "OpenADSConnection - Impossible de se contecter au routeur ADS. Veuillez vérifier que TwinCat est bien installé sur cet ordinateur et que l'application est en train de tourner."
        Return False
    End If
    If tcads.AdsServerAdsState = "INVALID" Then
        exception = "OpenADSConnection - Aucun serveur d'automation n'est joignable à l'adresse " & tcads.AdsAmsServerNetId & "::" & tcads.AdsAmsServerPort
        Return False
    End If
    Return True

End Function

UI冻结的特定行,需要花费大量时间才能执行:

tcads.AdsAmsConnect()

请注意,tcads参数实际上是一个必须直接添加到UI的AcviteX控件。我试图通过代码实例化一个,但它没有成功。所以它实际上是对Me.tcads的引用

该文件说明了关于该控制的内容:

  

ADS-OCX提供方法,事件和属性   能够通过TwinCAT与其他ADS设备交换信息   路由器。 ADS-OCX实现为ActiveX控件元素,和   基于Microsoft的COM技术。

可能是UI线程不喜欢我的连接线程正在使用其中一个控件的事实吗?

0 个答案:

没有答案