Can't this happen without using a lock? Simple consumer manufacturer

I have a queue, a list with producer threads and a list with consumer threads.

My code is as follows

    public class Runner
{
    List<Thread> Producers;
    List<Thread> Consumers;
    Queue<int> queue;
    Random random;

    public Runner()
    {
        Producers = new List<Thread>();
        Consumers = new List<Thread>();

        for (int i = 0; i < 2; i++)
        {
            Thread thread = new Thread(Produce);
            Producers.Add(thread);
        }

        for (int i = 0; i < 2; i++)
        {
            Thread thread = new Thread(Consume);
            Consumers.Add(thread);
        }

        queue = new Queue<int>();
        random = new Random();

        Producers.ForEach(( thread ) => { thread.Start(); });
        Consumers.ForEach(( thread ) => { thread.Start(); });
    }

    protected void Produce()
    {
        while (true)
        {
                int number = random.Next(0, 99);
                queue.Enqueue(number);
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " Produce: " + number);
        }
    }

    protected void Consume()
    {
        while (true)
        {
                if (queue.Any())
                {
                    int number = queue.Dequeue();
                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " Consume: " + number);
                }
                else
                {
                    Console.WriteLine("No items to consume");
                }
        }
    }
}

Should this not endure the unfortunate reason for not using the lock keyword? It failed once because it tried to remove from the queue when the queue was empty using the lock keyword, will fix this correctly?

If the lock keyword is not required for the above code, when necessary, then?

Thank you in advance! =)

+3
source share
6 answers

, . " ", .

, . , , . . .

+3

. , , ConcurrentQueue. Google "# ConcurrentQueue", , . ConcurrentQueue.

+3

, (, ), , - ​​ .

, ( ) , , - , , ( , , , , , ..). , "" - , , , , .

, , , , - ( ), ( , "" ). !

+2

, InvalidOperationException - " , ". , .

lock , Enqueue Dequeue - . - ConcurentQueues, . .

0

Yes, you must synchronize access to Queueit to make it thread safe. But you have one more problem. There is no mechanism that drives consumers to revolve around a cycle. Synchronizing access to Queueor using ConcurrentQueuewill not resolve this issue.

The easiest way to implement a producer-consumer pattern is to use a blocking queue. Fortunately, .NET 4.0 provides BlockingCollection, which, despite the name, is an implementation of a blocking queue.

public class Runner
{
    private BlockingCollection<int> queue = new BlockingCollection<int>();
    private Random random = new Random();

    public Runner()
    {
        for (int i = 0; i < 2; i++)
        {
            var thread = new Thread(Produce);
            thread.Start();
        }

        for (int i = 0; i < 2; i++)
        {
            var thread = new Thread(Consume);
            thread.Start();
        }
    }

    protected void Produce()
    {
        while (true)
        {
            int number = random.Next(0, 99);
            queue.Add(number);
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " Produce: " + number);
        }
    }

    protected void Consume()
    {
        while (true)
        {
            int number = queue.Take();
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " Consume: " + number);
        }
    }
}
0
source

All Articles