2

How to create one producer and two consumers with thread and task?

I tried many things: blocking collection, monitor.wait(enter,exit,pulse), semaphore, but can't seem to get it working.

Here is thread start:

private void button1_Click(object sender, EventArgs e)
{
    Thread Producer = new Thread(new ThreadStart(Task_Producer));
    Thread Consumer = new Thread(new ThreadStart(Task_Consumer));
    Thread Consumer2 = new Thread(new ThreadStart(Task_Consumer2));
    Producer.start();
    Consumer.start();
    Consumer2.start();
}

Here is threads:

private Task task1;
private Task task2;
private Task task3;
void Task_Producer()
{
task1 = Task.Factory.StartNew(Producer_t);
}
void Task_Consumer()
{
task2 = Task.Factory.StartNew(Consumer_t);
}
void Task_Consumer2()
{
task3 = Task.Factory.StartNew(Consumer_t2);
}

Here is task:

int i=0;
int how_much_numbers=1000;
int number=0;
private void Producer_t()
{
   for (i = 0; i < how_much_numbers;i++)  
    {
     //number=random number;
    }
}
private void Consumer_t()
{
   while (i<how_much_numbers)
        {
        //Check if number is fibonaci
        }
}
private void Consumer_t2()
{
   while (i<how_much_numbers)
        {
        //Check if number is primary
        }
}
d51
  • 316
  • 1
  • 6
  • 23
user3420235
  • 85
  • 1
  • 8
  • I trying to generate random number, when with other task check if random number is primary and when write to file, with other task check if is fibonaci and write to file. Need somehow generate random, when wait, when check if primary and fibonaci and when continue generating numbers. – user3420235 Mar 14 '14 at 14:40
  • 1
    What's keeping the consumers from missing a sequence of random numbers? How are the consumers being notified that a new number is available to be consumed? – crush Mar 14 '14 at 14:45
  • Here is global variable number and also global i. Who we can reach at any function in this class. But I dont know how to do, here need to wait somehow in random number task and in other continue random task job. http://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem – user3420235 Mar 14 '14 at 14:51
  • Why are you starting new threads just to start tasks? – Brian Rasmussen Mar 14 '14 at 15:27
  • I thought that I need thread and task. Its mine mistake :/ – user3420235 Mar 14 '14 at 15:52

1 Answers1

2

In this sample, threads and tasks are mixed, which is worse than wrong, it's useless as used to say one my teachers ;-)

Task.Factory.StartNew will have your code executed on a different thread. So from button1_Click, 3 threads will be started, and each one will push a new task to the thread pool through the task factory. At least one layer can be removed. Let say, for modernity's sake, remove the thread stuff and stick to the Task.Factory.StartNew, directly in the event handler.

According to this, the following code might do what you want :

public class ProducerConsumerTest
{
    private readonly BlockingCollection<int> _randomNumbersForFibonacci = new BlockingCollection<int>(10);
    private readonly BlockingCollection<int> _randomNumbersForPrime = new BlockingCollection<int>(10);

    int i = 0;
    int how_much_numbers = 20;
    int number = 0;
    private void Producer_t()
    {
        var random = new Random();

        for (i = 0; i < how_much_numbers; i++)
        {
            var randomNumber = random.Next();

            _randomNumbersForFibonacci.Add(randomNumber);
            _randomNumbersForPrime.Add(randomNumber);
        }
    }
    private void Consumer_t()
    {
        foreach (var randomNumber in _randomNumbersForFibonacci.GetConsumingEnumerable())
        {
            //Check if number is fibonaci
            Console.Out.WriteLine("IsFibonacci({0})", randomNumber);
        }
    }
    private void Consumer_t2()
    {
        foreach (var randomNumber in _randomNumbersForPrime.GetConsumingEnumerable())
        {
            //Check if number is primary
            Console.Out.WriteLine("IsPrime({0})", randomNumber);
        }
    }

    public void Run()
    {
        var producingTask = Task.Factory.StartNew(Producer_t);

        var fibonacciTask = Task.Factory.StartNew(Consumer_t);

        var primeTask = Task.Factory.StartNew(Consumer_t2);
    }
}

But you'll have to duplicate the collection to have every generated number analyzed by both tasks, because iterating through .GetConsumingEnumerable() removes the read element from the collection, so it can only be read once.

Community
  • 1
  • 1
Seb
  • 2,637
  • 1
  • 17
  • 15
  • Well, I wanted to upvote this because you're mostly right, but this is better served as a comment. – crush Mar 14 '14 at 14:42
  • Thanks for your answer. I understanded, that I just need use only threads or only task. But how to with first task generate random number when task wait, when in other task check if number is primary and in other if is fibonaci and when just continue generating number? – user3420235 Mar 14 '14 at 14:45
  • @crush : agreed for now. I'm elaborating, now that I know the purpose :-) – Seb Mar 14 '14 at 14:47
  • Ideal usage of `BlockingCollection` +1 – crush Mar 14 '14 at 15:24
  • @crush : thanks. If you had any idea to avoid duplicating the collection you would make me a happy man for the day ;-) – Seb Mar 14 '14 at 15:37
  • Well, you could create an object that contains a type of number based on an enum. If there are only two types, though, that is unnecessary work for GC. One thing to consider here is how fast numbers are produced in relation to how fast they are consumed. If they are produced faster than they are consumed, then it might be possible to run out of memory at some point. – crush Mar 14 '14 at 15:50
  • My first thought was to use publish/subscribe for this problem. Consumers would subscribe to the Producer. Producer would notify the consumers when a new number is ready. Each consumer would have a worker thread that processed an internal blocking collection. More or less, it boils down to the same thing you've got here, except your example sheds the complexities. – crush Mar 14 '14 at 15:56
  • When I run this code, nothing is printed on the console. Is there anything I need to add? – d51 Aug 20 '20 at 02:31
  • 1
    @dan51 You probably need to Task.WhenAll(producingTask, fibonacciTask, primeTask) to make your program wait for the 3 tasks to complete. – Seb Sep 04 '20 at 07:57