samedi 13 mars 2021

Random.Next() returning the same number multiple times in event handler

I am making a C# console app.

I have a class called Airline and another class called TravelAgency.

Airline.cs:

using System;
using System.Threading;

namespace App
{
    public delegate void PriceCutDelegate(string airlineId, int priceCut);

    class Airline
    {
        private int ticketsAvailable;
        private int ticketPrice;
        private int orderCounter;
        private int priceCutCounter;
        private PricingModel pricingModel;

        public static event PriceCutDelegate PriceCutEvent;

        public Airline()
        {
            ticketsAvailable = 100;
            ticketPrice = 500;
            orderCounter = 0;
            priceCutCounter = 0;
            pricingModel = new PricingModel();
        }

        public int GetTicketPrice()
        {
            return ticketPrice;
        }

        public void AirlineFunc()
        {
            while (priceCutCounter < 10)
            {
                Thread.Sleep(100);
                GenerateTicketPrice();

                String orderStr = Program.orderBuffer.GetOneCell(Thread.CurrentThread.Name);

                if (orderStr != null)
                {
                    OrderClass order = Decoder.DecodeOrder(orderStr);
                    Program.orderBuffer.sem.Release(1);
                    orderCounter++;
                    ticketsAvailable -= order.GetAmount();
                    OrderProcessing orderProc = new OrderProcessing(order);
                    Thread orderProcThread = new Thread(new ThreadStart(orderProc.ProcessNewOrder));
                    orderProcThread.Start();
                }
            }
            Program.airlineThreadCount--;
        }

        public void GenerateTicketPrice()
        {
            int newPrice = pricingModel.GenerateTicketPrice(ticketsAvailable, orderCounter);
            if (newPrice < ticketPrice)
            {
                if (PriceCutEvent != null)
                {
                    PriceCutEvent(Thread.CurrentThread.Name, newPrice);
                }

                priceCutCounter++;
                ticketPrice = newPrice;
            }
            else
                ticketPrice = newPrice;
        }
    }
}

TravelAgency.cs:

using System;
using System.Threading;

namespace App
{
    class TravelAgency
    {
        private int currentPrice;
        private bool placeOrder;
        private static OrderClass newOrder;
        private static object orderLock = new object();

        public TravelAgency()
        {
            currentPrice = 500;
            placeOrder = false;
            newOrder = null;
        }

        public void TravelAgencyFunc()
        {
            int orderCount = 0;
            while (Program.airlineThreadCount > 0)
            {
                if (placeOrder)
                {
                    orderCount++;
                    lock (orderLock)
                    {
                        newOrder.SetSenderId(Thread.CurrentThread.Name);
                        newOrder.SetTimestamp(DateTime.Now);

                        string orderStr = Encoder.EncodeOrder(newOrder);

                        Program.orderBuffer.sem.WaitOne();
                        Program.orderBuffer.SetOneCell(orderStr);

                        currentPrice = newOrder.GetUnitPrice();
                        placeOrder = false;
                    }
                }

                string confString = Program.confirmationBuffer.GetOneCell(Thread.CurrentThread.Name);

                if (confString != null)
                {
                    Program.confirmationBuffer.sem.Release(1);
                    OrderClass order = Decoder.DecodeOrder(confString);
                    Program.successCount++;
                }
            }
            Program.ordersCount += orderCount;
        }

        public void TicketPriceCut(string airlineId, int newPrice)
        {
            if (!placeOrder)
            {
                int orderAmount = 0;
                int priceDifference = currentPrice - newPrice;

                if (priceDifference > 0)
                {
                    if (priceDifference < 100)
                    {
                        orderAmount = 5;
                    }
                    else if (priceDifference < 300)
                    {
                        orderAmount = 15;
                    }
                    else if (priceDifference < 500)
                    {
                        orderAmount = 25;
                    }
                    else if (priceDifference <= 800)
                    {
                        orderAmount = 35;
                    }

                    lock (orderLock)
                    {
                        int randNum = Program.random.Next(4700, 7300);
                        newOrder = new OrderClass();
                        newOrder.SetCardNo(randNum);
                        newOrder.SetReceiverId(airlineId);
                        newOrder.SetAmount(orderAmount);
                        newOrder.SetUnitPrice(newPrice);
                        placeOrder = true;
                    }
                }
            }
        }
    }
}

Program.cs:

using System;
using System.Threading;

namespace App
{
    class Program
    {
        public static MultiCellBuffer orderBuffer = new MultiCellBuffer();
        public static MultiCellBuffer confirmationBuffer = new MultiCellBuffer();
        public static int airlineThreadCount = 0;
        public static int priceCutEventCount = 20;
        public static int ordersCount = 0;
        public static int successCount = 0;
        public static int rejectCount = 0;
        public static readonly Random random = new Random();

        public static void Main()
        {
            Airline[] airlines = new Airline[2];
            Thread[] airlineThreads = new Thread[2];

            TravelAgency[] travelAgencies = new TravelAgency[5];
            Thread[] travelAgencyThreads = new Thread[5];

            for (int i = 0; i < 2; i++)
            {
                airlines[i] = new Airline();
                airlineThreads[i] = new Thread(new ThreadStart(airlines[i].AirlineFunc));
                airlineThreads[i].Name = "AIRLINE " + i;
                airlineThreads[i].Start();
                airlineThreadCount++;
            }

            for (int i = 0; i < 5; i++)
            {
                travelAgencies[i] = new TravelAgency();
                travelAgencyThreads[i] = new Thread(new ThreadStart(travelAgencies[i].TravelAgencyFunc));
                travelAgencyThreads[i].Name = "TRAVEL AGENCY " + (i + 100);
                travelAgencyThreads[i].Start();
                Airline.PriceCutEvent += new PriceCutDelegate(travelAgencies[i].TicketPriceCut);
            }

            Thread.Sleep(500);

            orderBuffer.sem.Release(3);
            confirmationBuffer.sem.Release(3);

            for (int i = 0; i < 2; i++)
            {
                airlineThreads[i].Join();
            }

            for (int i = 0; i < 5; i++)
            {
                travelAgencyThreads[i].Join();
            }
        }
    }
}

The problem is: the randomly generated number randNum in TicketPriceCut in TravelAgency is always the same value for the same event emitted by Airline. I have multiple TravelAgency instances subscribed to the event PriceCutEvent in Airline, and I need randNum to be different for each one.

What should I do?

Edit: this question is different from Why does Random.Next() always return the same number because I am using the same instance of Random in my event handler. I am not creating a new Random instance every time I generate a new number. You can see this in the following snippet:

// In Program.cs:
public static readonly Random random = new Random();

// In TravelAgency.cs:
public void TicketPriceCut(string airlineId, int newPrice)
{
    // ...
    int randNum = Program.random.Next(4700, 7300);
    // ...
}



Aucun commentaire:

Enregistrer un commentaire