SOL1102
SOL1102

Reputation: 512

Running Different Processes In Multiple Threads Without Overlapping In VB.NET 2

I have a sub-procedure which I want to run a different process, depending on what is currently running. I thought the easiest way to do this was by using an ArrayList of each of the campaign details & adding an 'Inuse' field to check to see if the Inuse field is set to 0 or 1. The problem that I have is that when running the process it is all happening at once & the integer hasn't been changed before the next thread kicks in so my threads are running the same campaigns.

I tried to avoid the problem by adding a Thread.Sleep(100) delay inbetween starting threads but this led to exactly the same problem.

Here's an example of what I am trying to do:

    Imports System.Threading

Public Class Form1

    Private Campaigns As New ArrayList
    Private ProcessRunning As Boolean = False
    Friend StopProcess As Boolean = False

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        For i = 0 To Campaigns.Count - 1
            Dim objNewThread As New Thread(AddressOf RunProcess)
            objNewThread.IsBackground = True
            objNewThread.Start()
        Next
    End Sub

    Private Sub UpdateCells(ByVal CampID As Integer, ByVal Column As String, ByVal newText As String)
        Dim CellItemNum As Integer
        If Column = "Status" Then CellItemNum = 4
        DataGridView2.Rows(CampID).Cells.Item(CellItemNum).Value = newText
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For i As Integer = 0 To 10
            Campaigns.Add({Campaigns.Count(), "Campaign " & i, "Keywords " & i, "Link " & i, 5, True, 0, 0})
        Next
        DataGridView2.Rows.Clear()
        For Each Campaign In Campaigns
            DataGridView2.Rows.Add(New String() {Campaign(1), Campaign(2), Campaign(3), Campaign(6), ""})
        Next
    End Sub

    Private Sub RunProcess()
        ' Set Variables
        Dim CampID As Integer
        Dim CampName As String
        Dim Keywords As String
        Dim Link As String
        Dim CheckEvery As Integer
        Dim OkToUse As Boolean
        Dim Sent As Integer
        ' Find A Free Campaign
        For i As Integer = 0 To Campaigns.Count - 1
            ' Check If Inuse
            If Campaigns(i)(7) = 1 Then Continue For Else Campaigns(i)(7) = 1 ' This Line Sets Campaign To Inuse
            ' Most of the time only campaign(0) and campaign(1) are selected & multiple threads are running them instead of choosing unique campaigns
            ' Set Campaign Details
            CampID = Campaigns(i)(0)
            CampName = Campaigns(i)(1)
            Keywords = Campaigns(i)(2)
            Link = Campaigns(i)(3)
            CheckEvery = Campaigns(i)(4)
            OkToUse = Campaigns(i)(5)
            Sent = Campaigns(i)(6)
            ' Start Process
            UpdateCells(CampID, "Status", "Looking Up New Links (" & CampID & ")")
            Exit For
        Next
        While StopProcess = False
            Thread.Sleep(1000)
            UpdateCells(CampID, "Status", "Running Process (" & CampID & ")")
            Thread.Sleep(1000)
            For i = 0 To CheckEvery
                UpdateCells(CampID, "Status", "Re-Checking In " & (CheckEvery - i) & " Seconds")
                Thread.Sleep(1000)
            Next
        End While
        ' Closing Processes
        Campaigns(CampID)(7) = 0
    End Sub
End Class

Upvotes: 1

Views: 5269

Answers (2)

NickV
NickV

Reputation: 649

Try looking into QueueUserWorkItem():

Private Sub Button1_Click(ByVal sender As System.Object,
    ByVal e As System.EventArgs) Handles Button1.Click
    For i = 0 To Campaigns.Count - 1
        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf RunProcess), Campaigns[i])
    Next
End Sub

Then change the RunProcess() method to include the Campaign object sent in by the work item:

Private Sub RunProcess(ByVal o As System.Object)
    ' Process the Campaign
    Dim campaign As Campaign = Ctype(o, Campaign)
End Sub

There will be no need for inuse, plus threads will be managed by the managed ThreadPool!

Upvotes: 1

Jay
Jay

Reputation: 6017

You can use SyncLock to force your threads to wait.

class level so all threads access same lock

private myLock as new Object

Then use syncLock when you start your process and end it when you are done.

SyncLock myLock
  'process code here
End SyncLock

More MSDN info on the subject

Upvotes: 2

Related Questions