Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1114
  • Last Modified:

System.Threading.ThreadPool

how to pass values from a dataset to a method.
0
hrodriguez761
Asked:
hrodriguez761
  • 2
1 Solution
 
Carlos VillegasFull Stack .NET DeveloperCommented:
Hi buddy, you can use these approaches:

If you are using the .net framework 4.0 I highly recommend to use the new System.Threading.Tasks classes to do that instead of directly use the System.Threading.ThreadPool, because these new classes make the work easier, behind this is still using the ThreadPool class, this is an example of how to implement this method:
Public Class TasksTest
    ' Demo helper
    Shared myRnd As New Random

    Shared Sub StartMyTasks()
        ' To simulate the data to be processed
        Dim dtt As New System.Data.DataTable
        dtt.Columns.Add("Col1", GetType(Integer))
        dtt.Columns.Add("Col2", GetType(Integer))

        ' Data....
        dtt.Rows.Add(1, 1000)
        dtt.Rows.Add(1001, 2000)
        dtt.Rows.Add(2001, 3000)
        dtt.Rows.Add(3001, 4000)
        dtt.Rows.Add(4001, 5000)
        dtt.Rows.Add(5001, 6000)
        dtt.Rows.Add(6001, 7000)
        dtt.Rows.Add(7001, 8000)
        dtt.Rows.Add(8001, 9000)
        dtt.Rows.Add(9001, 10000)
        dtt.AcceptChanges()

        ' Set it to run 4 threads in parallel
        Dim po As New System.Threading.Tasks.ParallelOptions
        ' You will need to play with this number and see how much load can support your server hardware.
        ' A higher number necesarily dont meant a fast task completion because you can saturate the cpu, memory and IO resources.
        po.MaxDegreeOfParallelism = 4

        ' Create my delegate instance, indicating that my method paramter is of type System.Data.DataRow
        Dim myTaskAction As New Action(Of System.Data.DataRow)(AddressOf DoMyLongTimeConsumingTask)

        ' This will execute your task for each row in your data table ( see dtt.Select() ) and will take care of how many run at the same time.
        ' Better explained, it will call DoMyLongTimeConsumingTask method for each row passing it as parameter value.
        ' Also this line will stop your the main program execution until the task for each row is completed.
        System.Threading.Tasks.Parallel.ForEach(Of System.Data.DataRow)(dtt.Select(), po, myTaskAction)

        Console.WriteLine("Tasks Completed")
        Console.ReadLine()
    End Sub

    Shared Sub DoMyLongTimeConsumingTask(ByVal row As System.Data.DataRow)
        Dim col1Value As Integer = CType(row(0), Integer)
        Dim col2Value As Integer = CType(row(1), Integer)

        Console.WriteLine("Starting Thread; Col1=" & col1Value & ", Col2=" & col2Value)

        ' Simulate time consuming work...
        Dim timeSleeping As Integer = myRnd.Next(2000, 10000)
        System.Threading.Thread.Sleep(timeSleeping)

        Console.WriteLine("Completed Thread; Col1=" & col1Value & ", Col2=" & col2Value & "; " & timeSleeping & "ms")
    End Sub

End Class

Open in new window


To test this example just create a console application and call TasksTest.StartMyTasks() method from your Main sub.



Now, this the other method by using directly the System.Threading.ThreadPool class that is supported since the .net framework 1.0:
Public Class ThreadPoolTest
    ' Demo helper
    Shared myRnd As New Random

    Shared Sub StartMyTasks()
        Dim dtt As New System.Data.DataTable
        dtt.Columns.Add("Col1", GetType(Integer))
        dtt.Columns.Add("Col2", GetType(Integer))

        ' Simulate your data.
        dtt.Rows.Add(1, 1000)
        dtt.Rows.Add(1001, 2000)
        dtt.Rows.Add(2001, 3000)
        dtt.Rows.Add(3001, 4000)
        dtt.Rows.Add(4001, 5000)
        dtt.Rows.Add(5001, 6000)
        dtt.Rows.Add(6001, 7000)
        dtt.Rows.Add(7001, 8000)
        dtt.Rows.Add(8001, 9000)
        dtt.Rows.Add(9001, 10000)
        dtt.AcceptChanges()

        ' Setup ThreadPool behavior
        Dim workerThreads As Integer, completionPortThreads As Integer

        'Get the current MaxThreads ThreadPool settings
        System.Threading.ThreadPool.GetMaxThreads(workerThreads, completionPortThreads)

        ' Set it to run max 4 threads in parallel.
        ' You must take care of this setting because it will affect the ThreadPool class behavior for all your application instance.
        ' More info: http://msdn.microsoft.com/en-us/library/system.threading.threadpool.setmaxthreads.aspx
        System.Threading.ThreadPool.SetMaxThreads(4, completionPortThreads)

        'Excecute the task for each row in your data table.
        For Each row As System.Data.DataRow In dtt.Rows
            ' Add work to the Queue and pass row.ItemArray as parameter value
            System.Threading.ThreadPool.QueueUserWorkItem(New System.Threading.WaitCallback(AddressOf DoMyLongTimeConsumingTask), row.ItemArray)
        Next

        Console.ReadLine()
    End Sub

    Shared Sub DoMyLongTimeConsumingTask(ByVal p As Object)
        Dim myParams() As Object = CType(p, Object())
        Dim col1Value As Integer = CType(myParams(0), Integer)
        Dim col2Value As Integer = CType(myParams(1), Integer)

        Console.WriteLine("Starting Thread; Col1=" & col1Value & ", Col2=" & col2Value)

        ' Simulate time consuming work...
        Dim timeSleeping As Integer = myRnd.Next(2000, 10000)
        System.Threading.Thread.Sleep(timeSleeping)

        Console.WriteLine("Completed Thread; Col1=" & col1Value & ", Col2=" & col2Value & "; " & timeSleeping & "ms")
    End Sub

End Class

Open in new window


This method does not stop your main program execution, so if you want to wait for the task completion before continue it is required to implement a kind of signaling mechanism, maybe by using the System.Threading.ManualResetEvent class.

Also, to test this example, just create a console application and call ThreadPoolTest.StartMyTasks() method from your Main sub.

I hope this help.
0
 
hrodriguez761Author Commented:
@CodeCruiser - thanks that was Very informative.

@yv989c: Buddy you did it again - this works like a charm. - I  have another question how can i add a progress bar to this ( is possible at all??) since the task it's being split among x threads..

Thanks for your help guys
0
 
Carlos VillegasFull Stack .NET DeveloperCommented:
Hi, yes, it can be done, see the next example by using the first method explained here:
Public Class TasksTest
    ' Demo helper
    Shared myRnd As New Random
    Shared progressBar As System.Windows.Forms.ProgressBar

    Shared Sub StartMyTasks(ByVal progressBar As System.Windows.Forms.ProgressBar)
        TasksTest.progressBar = progressBar

        ' To simulate the data to be processed
        Dim dtt As New System.Data.DataTable
        dtt.Columns.Add("Col1", GetType(Integer))
        dtt.Columns.Add("Col2", GetType(Integer))

        ' Data....
        dtt.Rows.Add(1, 1000)
        dtt.Rows.Add(1001, 2000)
        dtt.Rows.Add(2001, 3000)
        dtt.Rows.Add(3001, 4000)
        dtt.Rows.Add(4001, 5000)
        dtt.Rows.Add(5001, 6000)
        dtt.Rows.Add(6001, 7000)
        dtt.Rows.Add(7001, 8000)
        dtt.Rows.Add(8001, 9000)
        dtt.Rows.Add(9001, 10000)
        dtt.AcceptChanges()

        ' Set the progress bar maximun.
        progressBar.Invoke(New Action(Of Integer)(AddressOf ProgressBarSetMaximun), dtt.Rows.Count)

        ' Set it to run 4 threads in parallel
        Dim po As New System.Threading.Tasks.ParallelOptions
        ' You will need to play with this number and see how much load can support your server hardware.
        ' A higher number necesarily dont meant a fast task completion because you can saturate the cpu, memory and IO resources.
        po.MaxDegreeOfParallelism = 4

        ' Create my delegate instance, indicating that my method paramter is of type System.Data.DataRow
        Dim myTaskAction As New Action(Of System.Data.DataRow)(AddressOf DoMyLongTimeConsumingTask)

        ' This will execute your task for each row in your data table ( see dtt.Select() ) and will take care of how many run at the same time.
        ' Better explained, it will call DoMyLongTimeConsumingTask method for each row passing it as parameter value.
        ' Also this line will stop your the main program execution until the task for each row is completed.
        System.Threading.Tasks.Parallel.ForEach(Of System.Data.DataRow)(dtt.Select(), po, myTaskAction)

        Console.WriteLine("Tasks Completed")
    End Sub

    Shared Sub DoMyLongTimeConsumingTask(ByVal row As System.Data.DataRow)
        Dim col1Value As Integer = CType(row(0), Integer)
        Dim col2Value As Integer = CType(row(1), Integer)

        Console.WriteLine("Starting Thread; Col1=" & col1Value & ", Col2=" & col2Value)

        ' Simulate time consuming work...
        Dim timeSleeping As Integer = myRnd.Next(2000, 10000)
        System.Threading.Thread.Sleep(timeSleeping)

        ' Update progress bar step
        progressBar.Invoke(New Action(AddressOf ProgressBarUpdate))

        Console.WriteLine("Completed Thread; Col1=" & col1Value & ", Col2=" & col2Value & "; " & timeSleeping & "ms")
    End Sub

    Private Shared Sub ProgressBarUpdate()
        SyncLock TasksTest.progressBar
            progressBar.Value += 1
        End SyncLock
    End Sub

    Private Shared Sub ProgressBarSetMaximun(ByVal max As Integer)
        progressBar.Maximum = max
    End Sub

End Class

Open in new window


Then from your windows form application, you can use a BackgroundWorker component to call TasksTest.StartMyTasks method (and passing your progressbar instance) by using the DoWork event, like the next example:
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
	TasksTest.StartMyTasks(ProgressBar1)
End Sub

Open in new window


To start the BackgroundWorker just call:
BackgroundWorker1.RunWorkerAsync()

Open in new window


BackgroundWorker1 represent the name of your BackgroundWorker component and ProgressBar1 represent the name of your progress bar control in your form.

I think the BackgroundWorker component is not required if you use the System.Threading.ThreadPool.QueueUserWorkItem method, I use that component for the first example because it stop the program execution when System.Threading.Tasks.Parallel.ForEach is called, maybe is there a way to change that behavior but I need to investigate more about this method to see if that is possible.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now