Results 1 to 11 of 11

Thread: [Resolved]Thread Pool Download Multiple Files at Once

  1. #1

    Thread Starter
    New Member
    Join Date
    Dec 2007
    Posts
    9

    Resolved [Resolved]Thread Pool Download Multiple Files at Once

    I'm trying to use the thread pool to download more than one string at a time. But most of the tutorial on threading is in C# or C++ so my knowledge on thread pool is limited.

    Here's what I got so far.
    Code:
    Imports System.Threading
    Imports System.Net
    Imports System.Text.RegularExpressions
    
    Public Class Example
    
        Private sLocation As String
        Private sName As String
        Private GameURL As String
    
        Private Sub Add()
            Dim dFile As New WebClient
            Dim FileStr As String
            FileStr = dFile.DownloadString(sLocation & sName)
            If Regex.IsMatch(FileStr, "(?<=<img src="")(.*?)(?="">)") = False Then Exit Sub
            ListBox1.Items.Add(sLocation & Regex.Match(FileStr, "(?<=<img src="")(.*?)(?="">)").Value)
        End Sub
    
        Private Sub Example_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            For Each FileLoc As String In IO.File.ReadAllLines(Application.StartupPath & "\Location.txt")
                For Each FileName As String In IO.File.ReadAllLines(Application.StartupPath & "\Name.txt")
                    sLocation = FileLoc
                    sName = FileName
                    ThreadPool.QueueUserWorkItem(AddressOf Add)
                Next
            Next
        End Sub
    End Class
    I keep getting an error "Cross-thread operation not valid: Control 'Listbox1' accessed from a thread other than the thread it was created on." And it still seems to be downloading it one by one to me.
    Last edited by SCRN; Sep 2nd, 2009 at 03:16 PM.

  2. #2
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Thread Pool Download Multiple Files at Once

    I'll take a look at your code but just to clarify the reason why you are getting that cross thread error is because you are trying to access a control (controls are created on the one and only UI thread) and controls cannot be updated from any thread other than the one they were created on. See JMC's guide to accessing controls from worker threads for info on how to work with this 'feature' - http://www.vbforums.com/showthread.php?t=498387

    EDIT: Looking at your code I think you need to start learning a bit more about how threading works. You are accessing the variables sLocation and sName from more than one thread at once, which is bound to cause either 1. exceptions to be thrown or 2. unexpected results.
    Basically when you call QueueUserWorkItem then that starts your Add routine on a 'worker' thread - this thread runs at the same time as the rest of your code, so while your code is still busy looping through your text file lines and setting the sLocation and sName variables, your worker threads are trying to read those same variables at the same time. The way you should do it is to declare those variables locally in your Example_Load event and then pass them in to the QueueUserWorkItem method (which in turn passes them in to your Add method). That way when your Add method executes it has its own 'private' copy of the variables that do not get modified when your loop carries on in the original thread (the UI thread).
    Last edited by chris128; Sep 2nd, 2009 at 01:20 PM.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  3. #3

    Thread Starter
    New Member
    Join Date
    Dec 2007
    Posts
    9

    Re: Thread Pool Download Multiple Files at Once

    Thanks for the reply, I fixed the access error but I still have no idea on how to download more than one at the same time.

    Code:
    Imports System.Threading
    Imports System.Net
    Imports System.Text.RegularExpressions
    
    Public Class Example
    
        Private sLocation As String
        Private sName As String
        Private FileStr As String
    
        Private Sub AddItem()
            ListBox1.Items.Add(sLocation & Regex.Match(FileStr, "(?<=<img src="")(.*?)(?="">)").Value)
        End Sub
    
        Private Sub Add()
            Dim dFile As New WebClient
            FileStr = dFile.DownloadString(sLocation & sName)
            If Regex.IsMatch(FileStr, "(?<=<img src="")(.*?)(?="">)") = False Then Exit Sub
            SyncLock ListBox1.GetType
                ListBox1.Invoke(CType(AddressOf AddItem, MethodInvoker))
            End SyncLock
        End Sub
    
        Private Sub Example_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            For Each FileLoc As String In IO.File.ReadAllLines(Application.StartupPath & "\Location.txt")
                For Each FileName As String In IO.File.ReadAllLines(Application.StartupPath & "\Name.txt")
                    sLocation = FileLoc
                    sName = FileName
                    ThreadPool.QueueUserWorkItem(AddressOf Add)
                Next
            Next
        End Sub
    End Class

  4. #4
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Thread Pool Download Multiple Files at Once

    You havent fixed the bits I mentioned though about those sLocation and sName variables being accessed by multiple threads at the same time. That could very well be what is causing you problems... and even if its not, it certainly will cause some problems or unexpected results.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  5. #5

    Thread Starter
    New Member
    Join Date
    Dec 2007
    Posts
    9

    Re: Thread Pool Download Multiple Files at Once

    Quote Originally Posted by chris128 View Post
    You havent fixed the bits I mentioned though about those sLocation and sName variables being accessed by multiple threads at the same time. That could very well be what is causing you problems... and even if its not, it certainly will cause some problems or unexpected results.
    I hope this is what you meant, sort of having a hard time grasping what you wrote.

    This code still seems to download one at a time, If you could, please provide any snippets or examples, that would be greatly appreciated.

    Code:
    Imports System.Threading
    Imports System.Net
    Imports System.Text.RegularExpressions
    
    Public Class TaskInfo
    
        Public Shared sLocation As String
        Public Shared sName As String
    
        Public Sub New(ByVal Loc As String, ByVal Str As String)
            sLocation = Loc
            sName = Str
        End Sub
    End Class
    
    Public Class Example
    
        Private FileStr As String
    
        Private Sub AddItem()
            ListBox1.Items.Add(TaskInfo.sLocation & Regex.Match(FileStr, "(?<=<img src="")(.*?)(?="">)").Value)
        End Sub
    
        Private Sub Add()
            Dim dFile As New WebClient
            FileStr = dFile.DownloadString(TaskInfo.sLocation & TaskInfo.sName)
            If Regex.IsMatch(FileStr, "(?<=<img src="")(.*?)(?="">)") = False Then Exit Sub
            SyncLock ListBox1.GetType
                ListBox1.Invoke(CType(AddressOf AddItem, MethodInvoker))
            End SyncLock
        End Sub
    
        Private Sub Example_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            For Each FileLoc As String In IO.File.ReadAllLines(Application.StartupPath & "\Location.txt")
                For Each FileName As String In IO.File.ReadAllLines(Application.StartupPath & "\Name.txt")
                    Dim ti As New TaskInfo(FileLoc, FileName)
                    ThreadPool.QueueUserWorkItem((AddressOf Add), ti)
                Next
            Next
        End Sub
    End Class

  6. #6
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Thread Pool Download Multiple Files at Once

    No thats not quite it, you have almost got it but the variables need to not be declared as Shared because that makes them accessible to everything still and not instance specific. That way you dont need a SyncLock in there (yours is in slightly the wrong place anyway though )
    Also, you need to change the signature of the Add method so that it accepts the instance of your TaskInfo class that you are passing in and the AddItem signature also needs to be changed.

    Here is how I would do it personally:

    This would be the TaskInfo class:
    vb Code:
    1. Public Class TaskInfo
    2.         Public sLocation As String
    3.         Public sName As String
    4.         Public FileStr As String
    5.  
    6.         Public Sub New(ByVal Loc As String, ByVal Str As String)
    7.             sLocation = Loc
    8.             sName = Str
    9.         End Sub
    10. End Class

    and this would be your Example class:
    vb Code:
    1. Public Class Example
    2.  
    3.         Private Sub AddItem(ByVal info As TaskInfo)
    4.             listbox1.Items.Add(info.sLocation & Regex.Match(info.FileStr, "(?<=<img src="")(.*?)(?="">)").Value)
    5.         End Sub
    6.  
    7.         Private Sub Add(ByVal info As Object)
    8.             Dim iTaskInfo As TaskInfo = DirectCast(info, TaskInfo)
    9.             Dim dFile As New WebClient
    10.             iTaskInfo.FileStr = dFile.DownloadString(iTaskInfo.sLocation & iTaskInfo.sName)
    11.             If Regex.IsMatch(iTaskInfo.FileStr, "(?<=<img src="")(.*?)(?="">)") = False Then Exit Sub
    12.             listbox1.Invoke(New Action(Of TaskInfo)(AddressOf AddItem), iTaskInfo)
    13.         End Sub
    14.  
    15.         Private Sub Example_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    16.             For Each FileLoc As String In IO.File.ReadAllLines(Application.StartupPath & "\Location.txt")
    17.                 For Each FileName As String In IO.File.ReadAllLines(Application.StartupPath & "\Name.txt")
    18.                     Dim ti As New TaskInfo(FileLoc, FileName)
    19.                     ThreadPool.QueueUserWorkItem((AddressOf Add), ti)
    20.                 Next
    21.             Next
    22.         End Sub
    23. End Class

    Note that I havent tested this, its just off the top of my head mostly so you might need to make some minor changes before it will work for you... Also I have stuck to the same variable names that you used originally (FileStr etc) - you might want to change this now so that all of the variables use the same format, i.e you have sLocation and sName so I'm guessing sFile would be apt for the FileStr name.
    Also its good practice to expose those Public variables in the TaskInfo class as properties rather than as fields but its not strictly necessary. An example of that would be:
    vb Code:
    1. Public Class TaskInfo
    2.  
    3.         Private _sFile As String
    4.         Public Property sFile() As String
    5.             Get
    6.                 Return _sFile
    7.             End Get
    8.             Set(ByVal value As String)
    9.                 _sFile = value
    10.             End Set
    11.         End Property
    12.  
    13.         Private _sLocation As String
    14.         Public Property sLocation() As String
    15.             Get
    16.                 Return _sLocation
    17.             End Get
    18.             Set(ByVal value As String)
    19.                 _sLocation = value
    20.             End Set
    21.         End Property
    22.  
    23.         Private _sName As String
    24.         Public Property sName() As String
    25.             Get
    26.                 Return _sName
    27.             End Get
    28.             Set(ByVal value As String)
    29.                 _sName = value
    30.             End Set
    31.         End Property
    32.  
    33.         Public Sub New(ByVal Loc As String, ByVal Str As String)
    34.             sLocation = Loc
    35.             sName = Str
    36.         End Sub
    37.  
    38. End Class

    That help?
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  7. #7

    Thread Starter
    New Member
    Join Date
    Dec 2007
    Posts
    9

    Re: Thread Pool Download Multiple Files at Once

    Thanks for the help, I tried increasing the speed with Threading.ThreadPool.SetMinThreads, but that doesn't seem to help. I'll read about encapsulating data structures with properties.

  8. #8
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Thread Pool Download Multiple Files at Once

    Have you actually tried the code I've provided above?
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  9. #9

    Thread Starter
    New Member
    Join Date
    Dec 2007
    Posts
    9

    Re: Thread Pool Download Multiple Files at Once

    Quote Originally Posted by chris128 View Post
    Have you actually tried the code I've provided above?
    Yes I did, it worked perfectly so I didn't change anything except the variable name you mentioned.

    Code:
    Imports System.Threading
    Imports System.Net
    Imports System.Text.RegularExpressions
    
    Public Class TaskInfo
        Public sLocation As String
        Public sName As String
        Public sFile As String
    
        Public Sub New(ByVal Loc As String, ByVal Str As String)
            sLocation = Loc
            sName = Str
        End Sub
    End Class
    
    Public Class Example
    
        Private Sub AddItem(ByVal info As TaskInfo)
            ListBox1.Items.Add(info.sLocation & Regex.Match(info.sFile, "(?<=<img src="")(.*?)(?="">)").Value)
        End Sub
    
        Private Sub Add(ByVal info As Object)
            Dim iTaskInfo As TaskInfo = DirectCast(info, TaskInfo)
            Dim dFile As New WebClient
            iTaskInfo.sFile = dFile.DownloadString(iTaskInfo.sLocation & iTaskInfo.sName)
            If Regex.IsMatch(iTaskInfo.sFile, "(?<=<img src="")(.*?)(?="">)") = False Then Exit Sub
            ListBox1.Invoke(New Action(Of TaskInfo)(AddressOf AddItem), iTaskInfo)
        End Sub
    
        Private Sub Example_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            For Each FileLoc As String In IO.File.ReadAllLines(Application.StartupPath & "\Location.txt")
                For Each FileName As String In IO.File.ReadAllLines(Application.StartupPath & "\Name.txt")
                    Dim ti As New TaskInfo(FileLoc, FileName)
                    ThreadPool.QueueUserWorkItem((AddressOf Add), ti)
                Next
            Next
        End Sub
    End Class

  10. #10
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Thread Pool Download Multiple Files at Once

    Oh right, I thought you would have mentioned that it worked in your last post, rather than just saying you still have a problem...
    If your original problem that you created this thread for is now working then you should mark this thread as Resolved (using the Thread Tools menu at the top of the page). If you have any more problems then open a new thread
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  11. #11

    Thread Starter
    New Member
    Join Date
    Dec 2007
    Posts
    9

    Re: Thread Pool Download Multiple Files at Once

    Quote Originally Posted by chris128 View Post
    Oh right, I thought you would have mentioned that it worked in your last post, rather than just saying you still have a problem...
    If your original problem that you created this thread for is now working then you should mark this thread as Resolved (using the Thread Tools menu at the top of the page). If you have any more problems then open a new thread
    Thanks, I'll see what I can work on from here.

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