Results 1 to 10 of 10

Thread: BackroundWorker Problem that I can't figure out

Hybrid View

  1. #1

    Thread Starter
    Member
    Join Date
    Aug 2012
    Location
    Nottingham, UK
    Posts
    44

    Question BackroundWorker Problem that I can't figure out

    Hello all, I have been having some trouble ever since I implemented this background worker code.

    My program simply loads a script (simply a file with one line containing a REGEX, although the script can contain more then one line of REGEX) and runs the check against everyline of every log file. When I run the script (by clicking Run) it seems to work perfectly, but if I either Press Stop, OR, wait for it to finish, the whole program freezes up for about 5 seconds, and then what I see in the first screenshot, turns into the second screenshot... Any help?





    This is just a snippet of the code, but I can post the whole lot upon request. Thanks
    Code:
    Imports System
    Imports System.IO
    Imports System.Text
    Imports System.Text.RegularExpressions
    Imports System.ComponentModel
    
    Public Class MainWindow
    
        Public num_logs As Integer
        Public num_scripts As Integer
        Public script_error As Integer
        Public script_edisc As String
        Public script_file As String
        Public script_letter As String
        Public script_loop As Decimal
        Public log_file As String
        Public log_letter As String
        Public log_loop As Decimal
        Public sr As StreamReader
        Public lr As StreamReader
        Public read_file_line As String
        Public current_script As String
        Public running_script As String
        Public script_line As String
        Public log_line As String
        Public script_param As Array
        Public script_text As String
        Public script_docu As String
        Public response As Boolean
        Public editmode As Integer
        Public script_regex As Regex
        Public script_m As Match
        Public running_bg As Integer
    
        Private Sub ToolStripButton5_Click(sender As System.Object, e As System.EventArgs) Handles ToolStripButton5.Click
            If (ListBox2.Items.Count < 1) Then
                MsgBox("There are no items in the script list. There needs to be at least one script selected before you can run it.", MsgBoxStyle.OkOnly, "Run Script")
            Else
                If (CheckedListBox1.Items.Count < 1) Then
                    MsgBox("The logs list is empty. There are no logs to run this script against.", MsgBoxStyle.OkOnly, "Run Script")
                Else
                    If Not BackgroundWorker1.IsBusy = True Then
                        BackgroundWorker1.RunWorkerAsync()
                        running_bg = 1
                    End If
    
    
                End If
            End If
    
    
        End Sub
    
    
        Private Sub MainWindow_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False
    
    ~ More Code ~
    
    End Sub
    
        Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            Dim worker As System.ComponentModel.BackgroundWorker
            worker = CType(sender, System.ComponentModel.BackgroundWorker)
    
            current_script = ListBox2.GetItemText(ListBox2.SelectedItem)
            TabControl1.SelectTab(1)
            If current_script <> "" Then
                running_script = "Running '" + current_script + "' script on selected log files..."
                al(running_script)
                script_error = 0
                script_edisc = ""
    
                For Each logfile In CheckedListBox1.CheckedItems()
    
                    log_file = ToolStripTextBox2.Text + "\" + logfile.ToString + ".log"
                    ListBox3.Items.Add("Running script on " + log_file + "...")
                    Me.Refresh()
                    lr = New StreamReader(log_file)
                    Do
                        log_line = lr.ReadLine()
                        If log_line <> "" Then
    
    
                            sr = New StreamReader("scripts/" + current_script + ".lcs")
                            Do
                                script_line = sr.ReadLine()
                                If (script_line <> "") Then
                                    If running_bg = 0 Then
    
                                        Exit Do
                                    End If
                                    If script_line.Length > 6 Then
                                        If (script_line.Substring(0, 6) = "MATCH ") Then
                                            Dim script_regex As New Regex(script_line.Substring(6))
                                            Dim script_m As Match = script_regex.Match(log_line)
                                            If script_m.Success Then
                                                ListBox3.Items.Add(log_line)
                                                Me.Refresh()
                                            End If
                                        End If
                                    End If
    
                                End If
    
                            Loop Until script_line Is Nothing
                        End If
                        If running_bg = 0 Then
                            Exit Do
                        End If
                    Loop Until log_line Is Nothing
                    ListBox3.Items.Add("Finished running script on " + log_file + "...")
                    Me.Refresh()
                    If running_bg = 0 Then
                        Exit For
                    End If
                Next
    
                al("Script has finished running.")
                Me.Refresh()
            End If
        End Sub
    
        Private Sub ToolStripButton11_Click(sender As System.Object, e As System.EventArgs) Handles ToolStripButton11.Click
            If BackgroundWorker1.WorkerSupportsCancellation = True Then
                BackgroundWorker1.CancelAsync()
                running_bg = 0
            End If
        End Sub
    
        Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted   
            If e.Error IsNot Nothing Then
                al("Error: " & e.Error.Message)
            ElseIf e.Cancelled Then
                al("Script did not finish as it was stopped.")
            Else
                al("Done!")
            End If
        End Sub
    
    
    End Class

  2. #2
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,464

    Re: BackroundWorker Problem that I can't figure out

    all of those controls you're accessing in your background thread need to be invoked on that thread

  3. #3

    Thread Starter
    Member
    Join Date
    Aug 2012
    Location
    Nottingham, UK
    Posts
    44

    Re: BackroundWorker Problem that I can't figure out

    I'm sorry, this is my first time using BackgroundWorkers, how does one invoke?

  4. #4
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,464

    Re: BackroundWorker Problem that I can't figure out

    here's an example:

    Code:
    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 Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            For x As Integer = 1 To 10
                setText(x.ToString)
                MsgBox(getText)
            Next
        End Sub
    
        Private Delegate Sub setTextCallBack(ByVal newValue As String)
        Private Sub setText(ByVal newValue As String)
            If TextBox1.InvokeRequired Then
                TextBox1.Invoke(New setTextCallBack(AddressOf setText), newValue)
            Else
                TextBox1.Text = newValue
            End If
        End Sub
    
        Private Delegate Function getTextCallBack() As String
        Private Function getText() As String
            If TextBox1.InvokeRequired Then
                Return DirectCast(TextBox1.Invoke(New getTextCallBack(AddressOf getText)), String)
            Else
                Return TextBox1.Text
            End If
        End Function
    
    End Class

  5. #5
    VB Addict Pradeep1210's Avatar
    Join Date
    Apr 2004
    Location
    Inside the CPU...
    Posts
    6,614

    Re: BackroundWorker Problem that I can't figure out

    Quote Originally Posted by .paul. View Post
    here's an example:

    Code:
    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 Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            For x As Integer = 1 To 10
                setText(x.ToString)
                MsgBox(getText)
            Next
        End Sub
    
        Private Delegate Sub setTextCallBack(ByVal newValue As String)
        Private Sub setText(ByVal newValue As String)
            If TextBox1.InvokeRequired Then
                TextBox1.Invoke(New setTextCallBack(AddressOf setText), newValue)
            Else
                TextBox1.Text = newValue
            End If
        End Sub
    
        Private Delegate Function getTextCallBack() As String
        Private Function getText() As String
            If TextBox1.InvokeRequired Then
                Return DirectCast(TextBox1.Invoke(New getTextCallBack(AddressOf getText)), String)
            Else
                Return TextBox1.Text
            End If
        End Function
    
    End Class
    While this would work, this seems to defeat the whole purpose of the BackgroundWorker class. The background worker class was really meant to avoid this type of code. It has all the logic already built into it.
    Whenever you want to access any UI element, do that via the ReportProgress method and ProgressChanged event. You can pass the ProgressPercentage to the ProgressReport method, telling it how much of your work is complete. Additionally you can pass it the UserState parameter with whatever value you want and do UI related things with that, if required. These two things are available for use in the ProgressChanged event handler.

    Here is an example of how to do it the proper way, avoiding delegates:
    Put a TextBox, a ProgressBar, and two Buttons on a form and the following code.
    vb.net Code:
    1. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    2.     ProgressBar1.Maximum = 100
    3.     ProgressBar1.Value = 0
    4.     BackgroundWorker1.WorkerReportsProgress = True
    5.     BackgroundWorker1.WorkerSupportsCancellation = True
    6.     BackgroundWorker1.RunWorkerAsync()
    7. End Sub
    8.  
    9. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    10.     ' Cancel button
    11.     BackgroundWorker1.CancelAsync()
    12. End Sub
    13.  
    14. Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    15.     Const MAX As Integer = 1000
    16.     For i As Integer = 1 To MAX
    17.         ' some delay to simulate work in progress
    18.         Threading.Thread.Sleep(100)
    19.  
    20.         ' report the progress to UI. You can optionally pass any values required to be accessed by UI elements.
    21.         Dim progress As Integer = (i * 100) \ MAX
    22.         BackgroundWorker1.ReportProgress(progress, i)
    23.         ' check if user wants to cancel this task. If Yes, then quit.
    24.         If BackgroundWorker1.CancellationPending Then
    25.             e.Cancel = True
    26.             Exit Sub
    27.         End If
    28.     Next
    29. End Sub
    30.  
    31. Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    32.     ProgressBar1.Value = e.ProgressPercentage
    33.     TextBox1.Text = e.UserState.ToString
    34. End Sub
    35.  
    36. Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    37.     If e.Cancelled Then
    38.         MessageBox.Show("Cancelled!")
    39.     Else
    40.         MessageBox.Show("Work done")
    41.     End If
    42. End Sub
    Run the program and first click Button1. It will start the background worker thread. Click Button2 anywhere in between to cancel it.
    Last edited by Pradeep1210; Oct 25th, 2013 at 09:24 AM. Reason: Corrected grammar and explained in detail.
    Pradeep, Microsoft MVP (Visual Basic)
    Please appreciate posts that have helped you by clicking icon on the left of the post.
    "A problem well stated is a problem half solved." — Charles F. Kettering

    Read articles on My Blog101 LINQ SamplesJSON ValidatorXML Schema Validator"How Do I" videos on MSDNVB.NET and C# ComparisonGood Coding PracticesVBForums Reputation SaverString EnumSuper Simple Tetris Game


    (2010-2013)
    NB: I do not answer coding questions via PM. If you want my help, then make a post and PM me it's link. If I can help, trust me I will...

  6. #6
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: BackroundWorker Problem that I can't figure out

    Why are you using a BackgroundWorker at all? It's pointless and quite wrong the way you're doing it. What are you actually trying to achieve? It's mind-boggling the number of people who ask for help and don't even tell us that. The whole point of using a BackgroundWorker is so that you DON'T have to do what .paul. is suggesting. It provides a model for multi-threading that involves just methods and events. If you're not using that model then you shouldn't be using a BackgroundWorker at all. So, explain what you're trying to achieve and then we might have a chance of explaining how to achieve it properly. Maybe it will involve a BackgroundWorker and maybe not. Maybe it will involve multi-threading and maybe not. The whole point of a BackgroundWorker is, as the name suggests, background work. Your DoWork event handler is accessing numerous UI elements so it is the very definition of foreground work, so the complete opposite of what it's for.

  7. #7
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,464

    Re: BackroundWorker Problem that I can't figure out

    @JM.

    there are cases where accessing controls from a secondary thread is unavoidable.
    BTW. I learned almost exactly that code from you in 2007

  8. #8
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: BackroundWorker Problem that I can't figure out

    Quote Originally Posted by .paul. View Post
    @JM.

    there are cases where accessing controls from a secondary thread is unavoidable.
    BTW. I learned almost exactly that code from you in 2007
    I didn't say that there was anything wrong with using delegation to access the UI from secondary threads. What I said was that the point of the BackgroundWorker was to perform the delegation for you so that you can just work with methods and events, which everyone's already familiar with anyway. That code is just bad use of a BackgroundWorker and adding lots of delegation is not the way to fix it. That code needs some real work.

  9. #9
    VB Addict Pradeep1210's Avatar
    Join Date
    Apr 2004
    Location
    Inside the CPU...
    Posts
    6,614

    Re: BackroundWorker Problem that I can't figure out

    You might want to have a look at this codebank thread:

    Correct way to use the BackgroundWorker
    Pradeep, Microsoft MVP (Visual Basic)
    Please appreciate posts that have helped you by clicking icon on the left of the post.
    "A problem well stated is a problem half solved." — Charles F. Kettering

    Read articles on My Blog101 LINQ SamplesJSON ValidatorXML Schema Validator"How Do I" videos on MSDNVB.NET and C# ComparisonGood Coding PracticesVBForums Reputation SaverString EnumSuper Simple Tetris Game


    (2010-2013)
    NB: I do not answer coding questions via PM. If you want my help, then make a post and PM me it's link. If I can help, trust me I will...

  10. #10

    Thread Starter
    Member
    Join Date
    Aug 2012
    Location
    Nottingham, UK
    Posts
    44

    Re: BackroundWorker Problem that I can't figure out

    Thanks for your help, I have removed all background worker elements in realising, this wasn't what they where to be used for.

    What I wanted, was a way to interupt the loop once the report had started to generate. I have changed my program so it asks you if you want to continue after finishing each log file.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width