0

I have an app that uses 5 concurrent threads to perform tasks. The threads will need to read from a list of items and pick the next available one. As soon as they've done so, they need to add one to the counter so that the next thread is able to pick the next one. I understand i will need to use something like BlockingCollection to do this so that 2 threads dont end up picking the same number and then both incrementing by one.

I'm a little stuck as to how this will work. I have declared by new BlockingCollection object but not sure where to proceed from here? Any help is much appreciated. Thanks.

Ed Jones
  • 321
  • 1
  • 2
  • 11
  • "The threads will need to read from a list of items and pick the next available one." -- this is exactly the use case for `BlockingCollection`. It's well-documented, you shouldn't have trouble finding the call you need on your thread to pull an item (if available). "As soon as they've done so..." -- the `BlockingCollection` takes care of all of this for you. It will ensure that one and only one thread gets an item. – Craig Aug 25 '20 at 16:00
  • Maybe I'm missing something in the part about "list of items" and "pick the next available one." Is there a fixed list of items that is rotating? Or is this a producer-consumer workflow where a producer is adding arbitrary items to be picked up by any one of a number of consumers? – Craig Aug 25 '20 at 16:01

1 Answers1

3

It sounds to me that you should be using a ConcurrentQueue(Of T). The whole point of a queue is that you can pick the next item off the front so if you use a queue data structure then there's no incrementing of any counter required. On top of that functionality provided by the Queue(Of T) class, the ConcurrentQueue(Of T) class is also thread-safe. Sounds rather like exactly what you need. Just call TryDequeue each time you want an item and it will return False when there are no more.

Try the following in a new Console Application project to see the principle in action:

Imports System.Collections.Concurrent
Imports System.Threading

Module Module1

    'A thread-safe queue containing numbers from 1 to 100.
    Private numbers As New ConcurrentQueue(Of Integer)(Enumerable.Range(1, 100))

    'Random number generator.
    Private rng As New Random

    Sub Main()
        'Read the queued numbers using five threads.
        For i = 1 To 5
            Call New Thread(AddressOf DisplayNumbers).Start()
        Next

        Console.ReadLine()
    End Sub

    Private Sub DisplayNumbers()
        Dim number As Integer

        'Try to get the next number until there are no more.
        Do While numbers.TryDequeue(number)
            'Display the number and the thread that read it.
            Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}; Number: {number}")

            'Wait a random time period.
            Thread.Sleep(rng.Next(500, 1000))
        Loop
    End Sub

End Module
jmcilhinney
  • 50,448
  • 5
  • 26
  • 46
  • Thanks for this, starting to understand it now! What is the significance of dim number as Integer? I am trying to incorporate this example into my code, and I have a variable that has the maximum number of items already. – Ed Jones Aug 25 '20 at 10:11
  • Ok ignore me, I get it now, this is working great! Thanks for your help – Ed Jones Aug 25 '20 at 11:02
  • 1
    Note that `BlockingCollection` mentioned in the question uses a `ConcurrentQueue` by default. – Craig Aug 25 '20 at 15:58