none
Backgroundworker 除錯出現「引動過程的目標傳回例外狀況」 RRS feed

  • 問題

  • 我一直在想辦法學會可以多執行緒,目前只些微會一點 Backgroundworker。
    在 Backgroundworker 中先查詢 EtherNet 有無連線,若有,就去讀取 PLC 的狀態輸出燈號來改變 Label 的顯示狀態,每隔100 ms 輪詢一次,
    就在去查詢 PLC 燈號時發生「引動過程的目標傳回例外狀況」,無解~~~找不出原因,
    想請各問大大幫我想辦法,或有沒有較好的輪詢寫法呢?

    底下是完整程式碼;


    Public Class Form1
        Private Class Connected
            Function PLC_Conn() As Boolean
                Return My.Computer.Network.IsAvailable
            End Function
        End Class

        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim conn As New Connected
            If conn.PLC_Conn Then
                Label1.Text = "連線"
            Else
                Label1.Text = "未連線"
            End If
            BackgroundWorker1.RunWorkerAsync(conn)
        End Sub

        Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            Dim conn As Connected = CType(e.Argument, Connected)
            Thread.Sleep(100)
        End Sub

        Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
            Dim conn As New Connected
            Dim PLC_work As Boolean
            PLC_work = conn.PLC_Conn
            If PLC_work Then
                Label2.Text = "連線"
                If SysmacCJ1.ReadMemoryBit(OMRON.Compolet.SYSMAC.SysmacCSBase.MemoryTypes.CIO, 1, 10) = True Then
                    Label25.Visible = False
                    Label22.Visible = True
                ElseIf SysmacCJ1.ReadMemoryBit(OMRON.Compolet.SYSMAC.SysmacCSBase.MemoryTypes.CIO, 1, 9) = True Then
                    Label24.Visible = False
                    Label21.Visible = True
                ElseIf SysmacCJ1.ReadMemoryBit(OMRON.Compolet.SYSMAC.SysmacCSBase.MemoryTypes.CIO, 1, 8) = True Then
                    Label23.Visible = False
                    Label20.Visible = True

                ElseIf SysmacCJ1.ReadMemoryBit(OMRON.Compolet.SYSMAC.SysmacCSBase.MemoryTypes.CIO, 1, 10) = False Then
                    Label25.Visible = True
                    Label22.Visible = False
                ElseIf SysmacCJ1.ReadMemoryBit(OMRON.Compolet.SYSMAC.SysmacCSBase.MemoryTypes.CIO, 1, 9) = False Then
                    Label24.Visible = True
                    Label21.Visible = False
                ElseIf SysmacCJ1.ReadMemoryBit(OMRON.Compolet.SYSMAC.SysmacCSBase.MemoryTypes.CIO, 1, 8) = False Then
                    Label23.Visible = True
                    Label20.Visible = False
                End If
            Else
                Label2.Text = "未連線"
            End If
                BackgroundWorker1.RunWorkerAsync(conn)
        End Sub

    2012年3月6日 上午 03:43

解答

所有回覆

  • 欲定時執行的工作用Timer控制會比較適合, 不用很忙碌的一直輪詢
    • 已標示為解答 C.Kevin 2012年3月7日 上午 06:19
    2012年3月6日 上午 07:47
  • 好~~我試試。
    2012年3月7日 上午 06:19
  • tihs 大大,

    我改用 Thread.Sleep(100) 當Timer ,在 BackgroundWorker1_RunWorkerCompleted 中加入 BackgroundWorker1.RunWorkerAsync() 去重複迴圈的動作,在 F5 偵錯都沒有問題,例外狀況都出現在 "停止偵錯",我按下停止偵錯時就會跳出來。

    我以為可能是 BackgroundWorker 還在執行工作時突然被中斷引發的,而我加入了 WndProc 去判斷假如按下 Form 右上角的 關閉叉叉 會去停止BackgrounderWorker 的工作,結果沒有效果,請問大大可以提示我解決問題的方向嗎?

    下方是重寫的程式碼,程式碼中的工作跟原本的不一樣,但出現的狀況一樣;

    Imports System.Threading
    Imports System.ComponentModel
    Imports System.Data.OleDb
    
    
    Public Class Form1
    
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            BackgroundWorker1.RunWorkerAsync()
        End Sub
    
    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    
    Dim CIO(5) As Integer
    Dim str As String = "Provider=Microsoft.Jet.Oledb.4.0;Data source=C:\Documents and Settings\Kevin\桌面\測試資料庫背景執行_BackgroundWorker\abc.mdb"
            Dim conn As OleDbConnection = New OleDbConnection(str)
            conn.Open()
    
            Dim str1 As String = "Insert Into W_DM (W0_0, W0_1, W0_2, W0_3, W0_4)Values(@W0_0, @W0_1, @W0_2, @W0_3, @W0_4)"
            Dim cmd As OleDbCommand = New OleDbCommand(str1, conn)
    
            For i = 0 To 4
                If BackgroundWorker1.CancellationPending Then
                    e.Cancel = True
                Else
                    Dim str2 As String = SysmacCJ1.ReadMemoryBit(OMRON.Compolet.SYSMAC.SysmacCSBase.MemoryTypes.WR, 0, i)
                    cmd.Parameters.AddWithValue("@W0_" & i, Trim(str2))
                    CIO(i) = CType(CBool(str2), Integer)
    e.Result = CIO
                End If
            Next
    
    If BackgroundWorker1.CancellationPending Then
                e.Cancel = True
            Else
                cmd.ExecuteNonQuery()
                conn.Close()
                Thread.Sleep(100)
            End If
    
    Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
            For i = 0 To 4
                Controls("Label" & i + 1).Text = e.Result(i)
            Next
            BackgroundWorker1.RunWorkerAsync()
        End Sub
    
        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
            If m.Msg = 161 And m.WParam = 20 Then
                BackgroundWorker1.CancelAsync()
                Me.Close()
    
            End If
            MyBase.WndProc(m)
        End Sub
    
    End Class




    • 已編輯 C.Kevin 2012年3月26日 上午 02:00
    2012年3月26日 上午 01:27
  • 您可以考慮直接使用Timer類別
    2012年3月26日 上午 01:44
  • BackgroundWorker1_RunWorkerCompleted 
    你在這一段程式碼並沒有判斷任何事情 ? 照理說, 如果下了 CancelAsync, 這邊就不應該再度呼叫 RunWorkAsync 了吧 ?

    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。


    2012年3月26日 上午 02:05
    版主
  • 我以為下了 CancelAsync 就不會觸發 RunWorkerCompleted 事件直接跳離 BackgroundWorker 了


      

          

    Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted

    Try If Not (e.Error Is Nothing) Then MessageBox.Show(e.Error.ToString) ElseIf e.Cancelled Then Exit Sub Else For i = 0 To 4 Controls("Label" & i + 1).Text = e.Result(i) Next BackgroundWorker1.RunWorkerAsync() End If Catch ex As Exception MessageBox.Show(ex.ToString) End Try

    End Sub

    我覺得很神奇,若上面的程式碼拿掉 Try...Catch... 至目前為止還沒有出現 "引動過程的目標傳回例外狀況" 錯誤,
    但拿掉 Try...Catch...就會出現,不過錯誤發生時 MessageBox 卻不會跳出來。
    可這樣不合理,既然拿掉 Try...Catch...有錯誤產生,加進 Try...Catch... 因該會抓住,@@

    (字的顏色怎麼變了?)


    • 已編輯 C.Kevin 2012年3月26日 上午 03:49
    2012年3月26日 上午 03:38
  • http://www.dotblogs.com.tw/billchung/archive/2009/05/30/8597.aspx

    這篇有討論 CancelAsync


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    2012年3月26日 上午 04:30
    版主
  • 瞭解了,謝謝 Bill 大大。

    Bill 大,您曉得 RunWorkerCompleted 的地方如果不加 Try...Catch...會出現 "引動過程的目標傳回例外狀況" ,加了 Try...Catch...就不出現了,
    您曉得為什麼嗎?

    我查了網路,網友的狀況是存取權限有關,我的程式碼全部就是看到的那樣,沒有什麼設定。

    2012年3月26日 上午 06:44
  • 基本上正確的寫法是, 當你的視窗要結束前, 它會先引發 Form Closing 事件, 你應該在 Form Closing 中檢查 BackGroundWorker 的 IsBusy 屬性, 決定是否真的要關閉視窗.


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    2012年3月26日 上午 07:12
    版主
  • 我將 WndProc 換成 Form Closing 事件了,有 Try...Catch...跟沒Try...Catch...的問題還是一樣。
    謝謝 Bill 大大。

    2012年3月26日 上午 08:07