1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Multithreading issue

Discussion in 'Visual Basic .NET' started by captchaman, Mar 24, 2011.

  1. captchaman

    captchaman Junior Member

    Joined:
    Sep 16, 2010
    Messages:
    190
    Likes Received:
    842
    Occupation:
    Software Programmer
    Location:
    USA
    I'm working on a program trying to add multithreading, but really what I'm doing here is opening a single thread so that the program doesn't freeze. Here's the basic pseudo code of what's messing up.
    Code:
    Imports System.Threading
    
    Public Class main
    
        Private Sub CheckPR()
    'This uses a function to check the pagerank and add to a listbox.
        End Sub
    
        Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick
            If lstQue.Items.Count > 0 Then
                Dim firstThread As New Thread(New ThreadStart(AddressOf CheckPR))
                firstThread.Start()
            End If
        End Sub
    
    End Class
    If there's anything in lstQue (the Queued listbox) then it needs to check the PR.

    Here's what it's doing: http://i.imgur.com/LZKXc.png

    Empty additions in the checked PR list. Why?
     
  2. eqsurplus

    eqsurplus Newbie

    Joined:
    May 16, 2009
    Messages:
    43
    Likes Received:
    8
    I don't think you've provided enough of the code to give you an answer.

    I would guess we need to see everything up to and including where you add the items to the list box.
     
  3. captchaman

    captchaman Junior Member

    Joined:
    Sep 16, 2010
    Messages:
    190
    Likes Received:
    842
    Occupation:
    Software Programmer
    Location:
    USA
    It worked perfectly fine with absolutely no skipping before I added multithreading. Now it checks but doesn't add the domain.

    rch

    Edit: I'm going to tinker with it some more then I'll post some of the relevant code.

    OK, here's the relevant code.
    Code:
        Private Sub CheckPR()
            Dim PR As String
            Dim HTML As String
            lstQue.SelectedIndex = 0
            HTML = OpenURL(frmSettings.PRURL.Text & "?url=" & lstQue.SelectedItem, cboTimeout.Text, False)
            Status.Text = "Checking: " & lstQue.Text
                PR = GetBetween(HTML, "PR|", "|PR")
                If PR >= cboPR.Text Then
                    AddNoDup(lstPR, "PR" & PR & " - " & lstQue.SelectedItem)
                lstQue.Items.Remove(lstQue.SelectedItem)
            Else
                'Error
            End If
        End Sub
    
        Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick
            If lstQue.Items.Count > 0 Then
                Dim firstThread As New Thread(New ThreadStart(AddressOf CheckPR))
                firstThread.Start()
            End If
        End Sub
    
        Public Function OpenURL(ByVal strURL As String, ByVal Timeout As String) As String
            Try
                Dim request As System.Net.HttpWebRequest = CType(System.Net.WebRequest.Create(strURL), System.Net.HttpWebRequest)
                request.Timeout = Timeout
                request.ReadWriteTimeout = Timeout
                Dim response As System.Net.HttpWebResponse = CType(request.GetResponse(), System.Net.HttpWebResponse)
                Dim receiveStream As System.IO.Stream = response.GetResponseStream()
                Dim readStream As New System.IO.StreamReader(receiveStream, System.Text.Encoding.UTF8)
                Dim s As String = readStream.ReadToEnd()
                response.Close()
                readStream.Close()
                Return s
    
            Catch webExcp As WebException
    
            Catch e As Exception
            End Try
    
        End Function
    
        Function AddNoDup(ByVal List As ListBox, ByVal msg As String)
            Dim X As Integer
            For X = 0 To List.Items.Count - 1
                If List.Items(X) = msg Then
                    GoTo qwerty
                End If
            Next X
            List.Items.Add(msg)
    qwerty:
            AddNoDup = ""
        End Function
     
    Last edited: Mar 24, 2011
  4. smack

    smack Junior Member

    Joined:
    Feb 1, 2010
    Messages:
    182
    Likes Received:
    78
    Occupation:
    Software Engineer/Evil Genius
    Location:
    inside .NET
    that's in a timer_tick event?

    what is the interval on the timer? you could be spawning up loads of threads very quickly.
     
  5. captchaman

    captchaman Junior Member

    Joined:
    Sep 16, 2010
    Messages:
    190
    Likes Received:
    842
    Occupation:
    Software Programmer
    Location:
    USA


    300. I though that only spawned a single thread.

    Edit: Changed to 1000, still errors and adds blanks.

    It's erroring on this line:
    Code:
    Status.Text = "Checking: " & lstQue.Text
    so obviously it's something isn't right with the url.
     
    Last edited: Mar 24, 2011
  6. smack

    smack Junior Member

    Joined:
    Feb 1, 2010
    Messages:
    182
    Likes Received:
    78
    Occupation:
    Software Engineer/Evil Genius
    Location:
    inside .NET
    no man, a timer is essentially a loop. if that collection had anything in it you would be spawning off a new thread every 300ms.

    that is actually the code for a timer control right, and not just an erroneously named method?
     
  7. captchaman

    captchaman Junior Member

    Joined:
    Sep 16, 2010
    Messages:
    190
    Likes Received:
    842
    Occupation:
    Software Programmer
    Location:
    USA
    Yes it's a timer.

    I'm not understanding. Right now I thought the code spawned 1 thread, checked PR, closed thread. Repeat.
     
    Last edited: Mar 24, 2011
  8. paincake

    paincake Power Member

    Joined:
    Aug 18, 2010
    Messages:
    716
    Likes Received:
    3,099
    Home Page:
    Concurrency is a hard beast to tame... I recommend reading "Concurrent Programming on Windows" by Joe Duffy
     
    • Thanks Thanks x 1
    Last edited: Mar 24, 2011
  9. smack

    smack Junior Member

    Joined:
    Feb 1, 2010
    Messages:
    182
    Likes Received:
    78
    Occupation:
    Software Engineer/Evil Genius
    Location:
    inside .NET
    no. you don't want to spawn that many threads.

    when you put a loop around your thread creation you want to be mindful that you're not spawning off too many of them. most normal computers will operate decent in between 10 - 50 threads depending on how much processing they're doing, obviously the more resources your machine has the more threads it can handle.

    you're also going to have to consider your locking in reference to that collection you're iterating over. you don't want to end up with dead locks or race conditions.

    this is why you should really consider a ground up rebuild of your application. if you don't plan properly for multithreading you're not going to get any advantages from it and will end up doing things like crashing your computer or just completely locking up the application.

    start small. make a loop that spawns 5 threads. use those 5 threads to pull things from your collection, and then loop back once they're finished with their processing and get more data.

    make sure you're conscious of your locks. you can use Mutex, SyncLock(), SemaphorSlim, etc... to maintain the integrity of your threads.
     
    • Thanks Thanks x 2
  10. captchaman

    captchaman Junior Member

    Joined:
    Sep 16, 2010
    Messages:
    190
    Likes Received:
    842
    Occupation:
    Software Programmer
    Location:
    USA
    Looks like it'll be a busy few days.

    Thanks for the help guys, I really appreciate it.

    - rch
     
  11. smack

    smack Junior Member

    Joined:
    Feb 1, 2010
    Messages:
    182
    Likes Received:
    78
    Occupation:
    Software Engineer/Evil Genius
    Location:
    inside .NET
    generally with these kind of programs you're going to want to use a modified producer/consumer model of threading. this is mainly for simplicities sake, there are all kinds of really interesting architectural nuances that you can develop once you get the hang of what you're doing. for now you should keep it simple.

    here is a simple way to spawn your threads. this can be called from a start button, or any other event/method that you would like to start the execution of your threads.

    Code:
    Dim i As Integer = 0
         For i = 1 To 6
           Dim mThread As New Thread(AddressOf MethodThatDoesWork)
           With mThread
             .IsBackground = True
             .Name = i.ToString()
             .Priority = ThreadPriority.Normal
             .Start()
         End With
    Next
    this will create 5 threads. now for the sake of arguments if you're using some kind of list or queue that you need to process the working method would look something like this:

    Code:
    Private MyCollection As Queue(Of String)
    Private Sub MethodThatDoesWork()
         Do
           Dim CollectionItem As String
           SyncLock(MyCollection)
             CollectionItem = MyCollection.Dequeue()
           End SyncLock
    
           ' Do Work.
    
         Loop Until MyCollection.Count = 0
    End Sub
    
     
    • Thanks Thanks x 3
  12. smack

    smack Junior Member

    Joined:
    Feb 1, 2010
    Messages:
    182
    Likes Received:
    78
    Occupation:
    Software Engineer/Evil Genius
    Location:
    inside .NET
    what's the exception it's generating? that could be a form cross call exception.

    whenever you spawn threads outside of your form thread and try to update something on the form that is considered an illegal thread cross call. you can suppress those exceptions, but it's generally not a good idea.

    what you're going to want to do is use a delegate like i mentioned in PM the other day with calls to RequireInvoke() and Invoke() on the control that you want to update.

    like this:

    http://www.blackhatworld.com/blackhat-seo/c-c-c/266798-form-multithreading-c.html#post2416449

    Code:
        Private Delegate Sub SetButtonEnabledDelegate(ByRef Enable As Boolean)
        Private Sub SetButtonEnabled(ByRef Enable As Boolean)
            Dim uDel As SetButtonEnabledDelegate
            If Me.InvokeRequired = True Then
                uDel = New SetButtonEnabledDelegate(AddressOf SetButtonEnabled)
                Me.Invoke(uDel, Enable)
            Else
                cmdImport.Enabled = Enable
            End If
        End Sub
    implementation would look like this:

    Code:
    Call SetButtonEnabled(True)
     
    • Thanks Thanks x 3
  13. eqsurplus

    eqsurplus Newbie

    Joined:
    May 16, 2009
    Messages:
    43
    Likes Received:
    8
    I suspect your getting blanks because another thread is interrupting the processing in the AddNoDupe function then returning where it left off but with the variable AddNoDup changed by the other thread.

    Try throwing a Synclock around the code in the AddNoDup function.
     
  14. gnote

    gnote Registered Member

    Joined:
    Mar 10, 2009
    Messages:
    80
    Likes Received:
    6
    Occupation:
    Programmer
    Location:
    USA
    You can't spawn a thread and expect it to directly update the main form. The GUI is loaded on a separate thread, and threads cannot modify each other directly.

    You need to create a callback and invoke the status update like smack said.

    You have a ways to go before you're a multithreading expert.. but if you learn this you should be able to fix your current issue.
     
  15. smack

    smack Junior Member

    Joined:
    Feb 1, 2010
    Messages:
    182
    Likes Received:
    78
    Occupation:
    Software Engineer/Evil Genius
    Location:
    inside .NET
    if you're really lazy and don't want to use the delegates there is a property you can set to suppress the cross call exceptions and allow for that kind of update to a form thread.

    Code:
    System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False
    this will work, but for obvious reasons is HIGHLY undesirable to implement. honestly i'm not even sure why it is provided. =)
     
  16. mailhelper

    mailhelper Registered Member

    Joined:
    Mar 23, 2011
    Messages:
    88
    Likes Received:
    10
    Occupation:
    Email Marketing Expert
    Location:
    Bangladesh
    Totally a funny code. You are trying to use Timer to re open a new thread with task. What happened if that thread is not finished and your timer triggers another thread? There is an easy solution for that. Use BackgroundWorker.
     
  17. mailhelper

    mailhelper Registered Member

    Joined:
    Mar 23, 2011
    Messages:
    88
    Likes Received:
    10
    Occupation:
    Email Marketing Expert
    Location:
    Bangladesh
    I was not able to post the modified code. Sorry for that.