none
VB2008 Thread之間的資料傳遞疑問 RRS feed

  • 問題

  • 請教各位大大, 目前我遇到一個問題

    以前PC對PLC 收集資料的量 , 走TCP/IP方式 約 0.3秒就收集完成

    由於目前客戶規劃的區塊很分散 整個系統需要的資料收集完成約0.8-1.2秒

    但目前還是希望畫面資訊能夠1秒更新一次 

    所以我目前開2個ThreadPool去作業實際測試

    ThreadPool 1 一直對PLC讀取資料 工作耗時0.4Sec

    ThreadPool 2 將監視資料放置於畫面上及資料處理作業  工作耗時0.8~1.1Sec

    但是若我將2各ThreadPool 同時啟用的話 畫面更新 有些欄位不會被更新到

    但已中斷去看確實是有執行畫面事卻無資訊

     ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf Read_Work), myResetEvent)
            ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf Read_PLC), myResetEvent)
    
     Private Sub Read_PLC()
            Do
                ' 
                 If Systeem_Start = True Then
                        TCP_READPLC
                    If First_Run = True Then
                        System.Threading.Thread.Sleep(500)
                        For x As Integer = 0 To 6000
                            myDataBuffer.M_DM(x) = myDataBuffer.DM(x)
                            myDataBuffer.M_H_Status(x) = myDataBuffer.H_Status(x)
                            myDataBuffer.M_W_Status(x) = myDataBuffer.W_Status(x)
                        Next
                        First_Run = False
                    End If
                              End If
               System.Threading.Thread.Sleep(100)
            Loop Until Systeem_Start = False
    
    
        End Sub
    
        Private Sub Read_Work()
            System.Threading.Thread.Sleep(2000)
            Do
                If Systeem_Start = True Then
                    Dim dateStart As DateTime
                    dateStart = Now
    
                    For i As Integer = 1 To 7
                        If First_Run = False Then
                                                  ChooseThreads(i)
                                                End If
                        System.Threading.Thread.Sleep(100)
                    Next
    
                    Systeem_Time_Display(Now.ToString("yyyy/MM/dd HH:mm:ss"))
                    Dim TS As TimeSpan = Now.Subtract(dateStart)
                    RunTimer = TS.TotalMilliseconds
                    CPU_Usage()
                            Else
    
                    If Systeem_Start = False Then
                        Exit Do
                    End If
    
                End If
            Loop
               End Sub
    
     Private Sub ChooseThreads(ByVal threadNumber As Integer)
            If Systeem_Start = True Then
                Select Case threadNumber
                    Case 1 'MAIN 資訊
                        
                        FactorialThread(1) = New System.Threading.Thread(AddressOf M_Display_Read)
                        FactorialThread(1).Start()
                     
                        'End If
                        'SyncLock Me
                        '    Dim Thread As New ParameterizedThreadStart(AddressOf M_Display_Read)
                        '    Thread(myDataBuffer.DM)
                        'End SyncLock
                    Case 2 '動作
                        FactorialThread(2) = New System.Threading.Thread(AddressOf Car_Status_Read)
                        FactorialThread(2).Start()
                        'Dim Thread As New ParameterizedThreadStart(AddressOf Car_Status_Read)
                        'Thread(myDataBuffer.DM)
                        
                    Case 3 '溫度資訊
                        FactorialThread(3) = New System.Threading.Thread(AddressOf Temp_Read)
                        FactorialThread(3).Start()
                        'Dim Thread As New ParameterizedThreadStart(AddressOf Temp_Read)
                        'Thread(myDataBuffer.DM)
                       
                    Case 4 '讀取ALARM
                        FactorialThread(4) = New System.Threading.Thread(AddressOf Alarm_Read)
                        FactorialThread(4).Start()
                        'Dim Thread As New ParameterizedThreadStart(AddressOf Alarm_Read)
                        'Thread(myDataBuffer.W_Status)
                       
                    Case 5 '異常燈號
                        FactorialThread(5) = New System.Threading.Thread(AddressOf Alarm_Lamp)
                        FactorialThread(5).Start()
                        'Dim Thread As New ParameterizedThreadStart(AddressOf Alarm_Lamp)
                        'Thread(myDataBuffer.W_Status)
                      )
                    Case 6 '數據監視
                        If TCP_ALM = False Then
                            FactorialThread(6) = New System.Threading.Thread(AddressOf ProFace_Check)
                            FactorialThread(6).Start()
                        End If
                    Case 7
                        FactorialThread(7) = New System.Threading.Thread(AddressOf Report_Watch)
                        FactorialThread(7).Start()
                      
                  
                End Select
            End If
        End Sub
    
    

    有試過Lock 功能 及 Thread 帶參數 還是會有更新過慢或不會更新的狀態

    所以針對  myDataBuffer.DM 這類的共用資料區塊在2個執行緒間要如何使用它,比較恰當?


    新手上路

    2018年6月6日 上午 03:58

解答

  • 一個 Process 只能有一個 GDIThread ,多個 WorkThread ,螢幕更新是委派給 GDIThread 執行。

    不精確的問法,就會得到隨便猜的答案;自己都不肯花時間好好描述問題,又何必期望網友會認真回答?

    • 已標示為解答 eblue 2018年6月15日 上午 05:29
    2018年6月11日 下午 03:00

所有回覆

  • 沒看到你如何更新螢幕的程式碼。

    如果你用 GDI Thread 來更新螢幕,含 work Thread 委派,你要確保你所有的工作都是用 Work Thread 跑,不能有任何會耗時的工作分給 GDI Thread 跑,否則會拖到螢幕更新。


    不精確的問法,就會得到隨便猜的答案;自己都不肯花時間好好描述問題,又何必期望網友會認真回答?

    2018年6月6日 下午 03:48
  • 心冷大大:

    畫面更新資訊就是將PLC 資料 分類 顯示於對應的DataGrdiview元件上 

    以溫度資訊為例

    myDataBuffer.Main_Temp 這個Table 是PLC DM區的位址參照表

       '溫度資訊顯示
        Private Sub Temp_Read()
            Dim item As String
            Dim PV As String
            Dim SV As String
            Dim ALM As String
            Dim Cooling As String
            For i As Integer = 1 To 24
                item = i
                Dim PV_DM As String = myDataBuffer.Main_Temp.Rows(i - 1).Item(2)
                Dim SV_DM As String = myDataBuffer.Main_Temp.Rows(i - 1).Item(3)
                Dim ALM_DM As String = myDataBuffer.Main_Temp.Rows(i - 1).Item(4)
                           Cooling = " "
                If i > 2 And i < 5 Then
                    Dim Cooling_DM As String = myDataBuffer.Main_Temp.Rows(i - 1).Item(5)
                    Cooling = (System.Convert.ToInt32(myDataBuffer.DM(Cool_DM), 16) / 10).ToString("0.0")
                End If
                PV = (System.Convert.ToInt32(myDataBuffer.DM(PV_DM), 16) / 10).ToString("0.0")
                SV = (System.Convert.ToInt32(myDataBuffer.DM(SV_DM), 16) / 10).ToString("0.0")
                ALM = (System.Convert.ToInt32(myDataBuffer.DM(ALM_DM), 16) / 10).ToString("0.0")
                Temp_Display(item, PV, SV, ALM, Cooling)
            Next
            
        End Sub
    
        Delegate Sub Temp_CallBack(ByVal item As String, ByVal PV As String, ByVal SV As String, ByVal ALM As String, ByVal Cooling As String)
        Private Sub Temp_Display(ByVal item As String, ByVal PV As String, ByVal SV As String, ByVal ALM As String, ByVal Cooling As String)
            If Me.DataGridView2.InvokeRequired Then
                Dim d As New Temp_CallBack(AddressOf Temp_Display)
                Me.Invoke(d, New Object() {item, PV, SV, ALM, Cooling})
            Else
                 DataGridView2.Rows(item).Cells(1).Value = PV
                 DataGridView2.Rows(item).Cells(2).Value = SV
                 DataGridView2.Rows(item).Cells(3).Value = ALM
                 DataGridView2.Rows(item).Cells(4).Value = Cooling
            End If
        End Sub

    Thread 中的

    第6 跟 第7 則是對應PLC資料變化而做資料紀錄工作 ,應該對畫面的更新沒有影響

    另外還有1個Timer元件 以每3分鐘為一個週期紀錄溫度曲線


    新手上路



    • 已編輯 eblue 2018年6月8日 上午 07:58
    2018年6月8日 上午 07:49
  • 你 Temp_Read 是 WorkThread

    你把 Temp_Display 多做了判斷才決定是否用 Temp_CallBack 委派,我是偏向分開來寫,這個邏輯好亂,委派的 sub 就單純一點純委派,這樣從邏輯上無法判斷你 Temp_Read 呼叫 Temp_Display 時,到底是 WorkThread 在更新螢幕還是委派 GDIThread 更新螢幕。


    不精確的問法,就會得到隨便猜的答案;自己都不肯花時間好好描述問題,又何必期望網友會認真回答?

    2018年6月8日 下午 05:10
  • 委派這個邏輯!之前也是可以正常顯示就沒再深入去探究他

    依據目前的CODE來看 我的確是把 GDIThread 包在WorkThread 中

    所以我把委派的部分 修改成這樣宣告這樣應該在更新的部分就都單純在WorkThread 中

    '在 Temp_Read 的區塊 傳值做修正

    Dim DataShow As New Temp_Display_Callback(AddressOf Temp_Display) DataShow.Invoke(Buffer) Delegate Sub Temp_CallBack(ByVal item As String, ByVal PV As String, ByVal SV As String, ByVal ALM As String, ByVal Cooling As String) Private Sub Temp_Display(ByVal item As String, ByVal PV As String, ByVal SV As String, ByVal ALM As String, ByVal Cooling As String) DataGridView2.Rows(item).Cells(1).Value = PV DataGridView2.Rows(item).Cells(2).Value = SV DataGridView2.Rows(item).Cells(3).Value = ALM DataGridView2.Rows(item).Cells(4).Value = Cooling End Sub



    新手上路

    2018年6月11日 上午 01:55
  • 一個 Process 只能有一個 GDIThread ,多個 WorkThread ,螢幕更新是委派給 GDIThread 執行。

    不精確的問法,就會得到隨便猜的答案;自己都不肯花時間好好描述問題,又何必期望網友會認真回答?

    • 已標示為解答 eblue 2018年6月15日 上午 05:29
    2018年6月11日 下午 03:00
  • 這樣看來是我的一開始邏輯架構錯了

    原本是預想1個WorkThread 去更新一個Datagridview元件,所以我畫面若有4個Datagridview元件

    我就會使用4個WorkThread去對應更新

    的確我有試過一個Process去呼叫2個GDIThread的委派作業 ,第2個會失效~~

    所以基本上 我應該是 只開一個Process 去執行 GDIThread來更新畫面上所有顯示資訊區塊


    新手上路

    2018年6月15日 上午 02:04