Ejemplo n.º 1
0
        public static void CommunicatorThread()
        {
            while (true)
            {
                waitForCommunicationHandle.WaitOne();
                int[] msgArray = new int[4 + journal.processesNumber];
                var   request  = comm.ImmediateReceive(Communicator.anySource, Communicator.anyTag, msgArray);
                waitForCommunicationHandle.Set();

                CompletedStatus probeResult = null;
                while (probeResult == null)
                {
                    waitForCommunicationHandle.WaitOne();
                    probeResult = request.Test();
                    waitForCommunicationHandle.Set();
                    Thread.Sleep(20);
                }

                waitForCommunicationHandle.WaitOne();

                //Obsłużenie otrzymania zgody
                if (probeResult.Tag == MSG_ACCEPT)
                {
                    AcceptMessage msg = MessageArrays.AcceptArrayToMsg(msgArray);
                    journal.CompareTimestampsAndUpdate(msg.Timestamp);
                    journal.IncrementTimestamp();

                    //Console.WriteLine($"Proces {journal.shipRank}: dostałem ACCEPT od procesu {msg.SenderRank}.");

                    journal.Accepts.Add(msg);
                    if (journal.RememberedClock < msg.LogicalClock)                     //sprawdzenie zegara i zapamiętanie danych z wiadomości, jeśli nowszy
                    {
                        journal.RememberedClock           = msg.LogicalClock;
                        journal.RememberedOccupancy       = msg.CurrentOccupancy;
                        journal.RememberedLeavingCounters = msg.LeavingCounters;

                        //Console.WriteLine($"Proces {journal.shipRank}: Dostałem zgodę ze świeższym statusem, od procesu {msg.SenderRank}, według niego zajętość to {msg.CurrentOccupancy}.");
                    }

                    if (journal.Accepts.Count == journal.processesNumber - 1)                     //wszystkie zgody otrzymane
                    {
                        journal.CanalOfInterest.CompareClocksAndUpdate(journal.RememberedClock);
                        journal.CanalOfInterest.CurrentOccupancy = journal.RememberedOccupancy;
                        journal.CanalOfInterest.CurrentOccupancy++;

                        //oznaczamy miejsca zwolnione przez procesy, o których wiemy, że wyszły z kanału, a wysyłający nam najświeższą zgodę nie zdążył się o tym dowiedzieć przed wysłaniem
                        for (int i = 0; i < msg.LeavingCounters.Count; i++)
                        {
                            if (journal.CanalOfInterest.LeavingCounters[i] > journal.RememberedLeavingCounters[i])
                            {
                                //Console.WriteLine($"Proces {journal.shipRank}: MUSZĘ ZAKTUALIZOWAĆ CURRENT OCCUPANCY! Według mnie leaving counter dla procesu {i} wynosi {journal.CanalOfInterest.LeavingCounters[i]}, a według drugiego procesu {journal.RememberedLeavingCounters[i]}.");
                                journal.CanalOfInterest.CurrentOccupancy -= journal.CanalOfInterest.LeavingCounters[i] - journal.RememberedLeavingCounters[i];
                            }
                            if (journal.CanalOfInterest.LeavingCounters[i] < journal.RememberedLeavingCounters[i])
                            {
                                journal.CanalOfInterest.LeavingCounters[i] = journal.RememberedLeavingCounters[i];
                            }
                        }

                        journal.IsDemandingEntry = false;
                        journal.CanalOfInterest.IncrementClock();

                        if (journal.CanalOfInterest.CurrentOccupancy == journal.CanalOfInterest.maxOccupancy)                         //jeśli jesteśmy ostatnim mieszczącym się w kanale procesem
                        {
                            //Console.WriteLine($"Proces {journal.shipRank}: kanał {journal.CanalOfInterest.ID} jest teraz pełny.");
                            journal.IsBlockingCanalEntry = true;
                        }
                        else                         //jeśli uważamy, że jest jeszcze miejsce (nie jesteśmy ostatnim mieszczącym się procesem), wysyłamy zgody wszystkim, którzy czekają
                        {
                            int        currentOccupancy = journal.CanalOfInterest.CurrentOccupancy;
                            int        logicalClock     = journal.CanalOfInterest.LogicalClock;
                            List <int> leavingCounters  = journal.CanalOfInterest.LeavingCounters;
                            journal.IncrementTimestamp();
                            AcceptMessage accept      = new AcceptMessage(journal.shipRank, journal.Timestamp, currentOccupancy, logicalClock, leavingCounters);
                            int[]         acceptArray = MessageArrays.AcceptMsgToArray(accept);

                            foreach (DemandMessage demand in journal.DemandsForSameDirection)
                            {
                                comm.Send(acceptArray, demand.SenderRank, MSG_ACCEPT);
                                //Console.WriteLine($"Proces {journal.shipRank}: po moim wejściu kanał ma jeszcze miejsce, więc wysyłam ACCEPT do procesu {demand.SenderRank} do kanału {demand.Canal}.");
                            }
                            journal.DemandsForSameDirection.Clear();
                        }

                        journal.Accepts.Clear();
                        waitForAcceptsHandle.Set();                         //zwolnienie blokady
                    }
                }

                //Obsłużenie otrzymania żądania
                if (probeResult.Tag == MSG_DEMAND)
                {
                    DemandMessage msg = MessageArrays.DemandArrayToMsg(msgArray);
                    journal.CompareTimestampsAndUpdate(msg.Timestamp);
                    journal.IncrementTimestamp();

                    //Console.WriteLine($"Proces {journal.shipRank}: dostałem DEMAND od procesu {msg.SenderRank}.");

                    bool accept = false;
                    if (msg.Direction != journal.DirectionOfInterest)                                   //jeśli żądany jest przeciwny kierunek do naszego
                    {
                        if (journal.CanalOfInterest == null || msg.Canal != journal.CanalOfInterest.ID) //jeśli żądany jest kanał, który nas nie obchodzi
                        {
                            accept = true;
                        }
                        else if (journal.IsDemandingEntry && (msg.Timestamp < journal.MyDemandTimestamp || (msg.Timestamp == journal.MyDemandTimestamp && msg.SenderRank > journal.shipRank)))                         //jeśli nie jesteśmy jeszcze w kanale, a konkurujący ma starsze żądanie (niższy timestamp) lub tak samo stare żądanie, lecz wyższą rangę
                        {
                            accept = true;
                        }
                    }
                    else                                                                                //jeśli żądany jest ten sam kierunek
                    {
                        if (journal.CanalOfInterest == null || msg.Canal != journal.CanalOfInterest.ID) //jeśli żądany jest kanał, który nas nie obchodzi
                        {
                            accept = true;
                        }
                        else if (journal.IsDemandingEntry && (msg.Timestamp < journal.MyDemandTimestamp || (msg.Timestamp == journal.MyDemandTimestamp && msg.SenderRank > journal.shipRank)))                         //jeśli nie jesteśmy jeszcze w kanale, a konkurujący ma starsze żądanie (niższy timestamp) lub tak samo stare żądanie, lecz wyższą rangę
                        {
                            accept = true;
                        }
                        else if (!journal.IsDemandingEntry && !journal.IsBlockingCanalEntry)                         //jeśli jesteśmy w kanale (nie ubiegamy się o dostęp), ale nie blokujemy dostępu do kanału
                        {
                            accept = true;
                        }
                    }

                    if (accept)
                    {
                        Canal      desiredCanal     = journal.ExistingCanals[msg.Canal];
                        int        currentOccupancy = desiredCanal.CurrentOccupancy;
                        int        logicalClock     = desiredCanal.LogicalClock;
                        List <int> leavingCounters  = desiredCanal.LeavingCounters;
                        journal.IncrementTimestamp();
                        //Console.WriteLine($"Proces {journal.shipRank}: Wysyłam zgodę procesowi {msg.SenderRank} do kanału {msg.Canal}, według mnie leaving counter żądającego w żądanym kanale to {leavingCounters[msg.SenderRank]}.");
                        AcceptMessage acceptMessage = new AcceptMessage(journal.shipRank, journal.Timestamp, currentOccupancy, logicalClock, leavingCounters);
                        int[]         acceptArray   = MessageArrays.AcceptMsgToArray(acceptMessage);
                        string        logString     = $"Proces {journal.shipRank}: wysyłana zgoda ma następujące wartości pól - Ranga: {acceptMessage.SenderRank}, Zajętość: {acceptMessage.CurrentOccupancy}, Zegar: {acceptMessage.LogicalClock}, Leaving counters: ";
                        foreach (int process in acceptMessage.LeavingCounters)
                        {
                            logString += $"{process} ";
                        }
                        //Console.WriteLine(logString);
                        comm.Send(acceptArray, msg.SenderRank, MSG_ACCEPT);
                    }
                    else

                    {
                        if (msg.Direction == journal.DirectionOfInterest)
                        {
                            journal.DemandsForSameDirection.Add(msg);
                        }
                        else
                        {
                            journal.DemandsForOppositeDirection.Add(msg);
                        }
                    }
                }

                //Obsłużenie otrzymania wiadomości o wyjściu z kanału
                if (probeResult.Tag == MSG_LEAVE)
                {
                    LeaveMessage msg = MessageArrays.LeaveArrayToMsg(msgArray);
                    journal.CompareTimestampsAndUpdate(msg.Timestamp);
                    journal.IncrementTimestamp();

                    Canal canal = journal.ExistingCanals[msg.Canal];

                    //Jeżeli jeszcze nie wiemy o tym wyjściu
                    if (canal.LeavingCounters[msg.SenderRank] < msg.LeavingCounter)
                    {
                        //Console.WriteLine($"Proces {journal.shipRank}: dostałem LEAVE od procesu {msg.SenderRank} z kanału {msg.Canal}, jego leaving counter to {msg.LeavingCounter}, a mój {canal.LeavingCounters[msg.SenderRank]}.");

                        //Aktualizacja licznika wyjść procesu z kanału
                        canal.LeavingCounters[msg.SenderRank] = msg.LeavingCounter;

                        //Jeśli jesteśmy blokującym procesem w tym kanale, zwalniamy miejsce i wysyłamy zgodę wszystkim na naszej liście oczekujących w tym samym kierunku
                        canal.CurrentOccupancy--;

                        if (journal.CanalOfInterest != null && journal.CanalOfInterest.ID == msg.Canal && journal.IsBlockingCanalEntry)
                        {
                            int        currentOccupancy = canal.CurrentOccupancy;
                            int        logicalClock     = canal.LogicalClock;
                            List <int> leavingCounters  = canal.LeavingCounters;
                            journal.IncrementTimestamp();
                            AcceptMessage accept      = new AcceptMessage(journal.shipRank, journal.Timestamp, currentOccupancy, logicalClock, leavingCounters);
                            int[]         acceptArray = MessageArrays.AcceptMsgToArray(accept);

                            foreach (DemandMessage demand in journal.DemandsForSameDirection)
                            {
                                comm.Send(acceptArray, demand.SenderRank, MSG_ACCEPT);
                            }

                            journal.IsBlockingCanalEntry = false;
                            journal.DemandsForSameDirection.Clear();
                        }
                    }
                }

                waitForCommunicationHandle.Set();
            }
        }
Ejemplo n.º 2
0
        //mpiexec -np 4 CzerwonyPazdziernik.exe
        static void Main(string[] args)
        {
            MPI.Environment.Run(ref args, Threading.Multiple, receivedComm =>
            {
                //Inicjalizacja
                comm    = receivedComm;
                journal = new ShipJournal(canalCapacities, comm.Size, comm.Rank);

                //Inicjalizacja losowości
                Thread.Sleep(comm.Rank);
                rand = new Random();

                //Uruchomienie wątku komunikacyjnego
                Thread communicator = new Thread(new ThreadStart(CommunicatorThread));
                communicator.Start();

                //Console.WriteLine($"Proces {journal.shipRank}: jest łącznie {journal.processesNumber} procesów.");

                while (true)
                {
                    //Console.WriteLine($"Proces {journal.shipRank}: rozpoczynam lokalne przetwarzanie.");

                    //Symulacja lokalnego przetwarzania (magazynowanie/ameryka)
                    Thread.Sleep(rand.Next(4) * speed);

                    waitForCommunicationHandle.WaitOne();
                    {
                        //Wylosuj obiekt pożądania (kanał)
                        journal.CanalOfInterest = journal.ExistingCanals[rand.Next(journal.ExistingCanals.Count)];

                        //Console.WriteLine($"Proces {journal.shipRank}: ubiegam się o kanał o numerze {journal.CanalOfInterest.ID}.");

                        //Wyślij żądania i ustaw remembered leaving counters na własne (jesteśmy "swoją pierwszą zgodą")
                        journal.IsDemandingEntry          = true;
                        journal.RememberedClock           = journal.CanalOfInterest.LogicalClock;
                        journal.RememberedOccupancy       = journal.CanalOfInterest.CurrentOccupancy;
                        journal.RememberedLeavingCounters = journal.CanalOfInterest.LeavingCounters;
                        journal.IncrementTimestamp();
                        journal.MyDemandTimestamp = journal.Timestamp;
                        DemandMessage demand      = new DemandMessage(journal.shipRank, journal.Timestamp, journal.CanalOfInterest.ID, journal.DirectionOfInterest);
                        int[] demandArray         = MessageArrays.DemandMsgToArray(demand);
                        for (int i = 0; i < journal.processesNumber; i++)
                        {
                            if (i != journal.shipRank)
                            {
                                comm.Send(demandArray, i, MSG_DEMAND);
                            }
                        }
                    }
                    waitForCommunicationHandle.Set();

                    //Czekaj na sygnał od drugiego wątku, że mamy już wszystkie zgody
                    waitForAcceptsHandle.WaitOne();

                    Console.WriteLine($"Proces {journal.shipRank}: wchodzę do kanału o numerze {journal.CanalOfInterest.ID} i rozpoczynam podróż w kierunku {journal.DirectionOfInterest}. Według mnie zajętość kanału to {journal.CanalOfInterest.CurrentOccupancy}/{journal.CanalOfInterest.maxOccupancy}");
                    if (journal.CanalOfInterest.CurrentOccupancy == 0)
                    {
                        throw new Exception("Dotarliśmy do zera");
                    }

                    //Symulacja lokalnego przetwarzania (podróż kanałem)
                    Thread.Sleep(rand.Next(4) * speed);

                    string printDirection = journal.DirectionOfInterest == Directions.WEST ? "zachodzie" : "wschodzie";
                    Console.WriteLine($"Proces {journal.shipRank}: opuszczam kanał o numerze {journal.CanalOfInterest.ID}. Znajduję się teraz na {printDirection}.");

                    waitForCommunicationHandle.WaitOne();
                    {
                        //Zinkrementuj licznik wyjść z kanału i wyślij informację o wyjściu
                        journal.CanalOfInterest.LeavingCounters[journal.shipRank]++;
                        //Console.WriteLine($"Proces {journal.shipRank}: mój leaving counter kanału to: {journal.CanalOfInterest.LeavingCounters[journal.shipRank]}.");
                        journal.IncrementTimestamp();
                        LeaveMessage leave = new LeaveMessage(journal.shipRank, journal.Timestamp, journal.CanalOfInterest.ID, journal.CanalOfInterest.LeavingCounters[journal.shipRank]);
                        int[] leaveArray   = MessageArrays.LeaveMsgToArray(leave);
                        for (int i = 0; i < journal.processesNumber; i++)
                        {
                            if (i != journal.shipRank)
                            {
                                comm.Send(leaveArray, i, MSG_LEAVE);
                            }
                        }

                        //Obniż zajętość i wyślij naszą zgodę na wejście tych, którzy chcieli wejść z przeciwnej strony (niech drugi wątek w tym nie przeszkadza, np. przez dodawanie nowych żądań do listy)
                        journal.CanalOfInterest.CurrentOccupancy--;
                        int currentOccupancy       = journal.CanalOfInterest.CurrentOccupancy;
                        int logicalClock           = journal.CanalOfInterest.LogicalClock;
                        List <int> leavingCounters = journal.CanalOfInterest.LeavingCounters;
                        journal.IncrementTimestamp();
                        AcceptMessage accept = new AcceptMessage(journal.shipRank, journal.Timestamp, currentOccupancy, logicalClock, leavingCounters);
                        int[] acceptArray    = MessageArrays.AcceptMsgToArray(accept);
                        foreach (DemandMessage demand in journal.DemandsForOppositeDirection)
                        {
                            comm.Send(acceptArray, demand.SenderRank, MSG_ACCEPT);
                            //Console.WriteLine($"Proces {journal.shipRank}: po wyjściu wysłałem procesowi {demand.SenderRank} ACCEPT do kanału {demand.Canal} (ten sam kierunek).");
                            string logString = $"Proces {journal.shipRank}: wysyłana zgoda ma następujące wartości pól - Ranga: {accept.SenderRank}, Zajętość: {accept.CurrentOccupancy}, Zegar: {accept.LogicalClock}, Leaving counters: ";
                            foreach (int process in accept.LeavingCounters)
                            {
                                logString += $"{process} ";
                            }
                            //Console.WriteLine(logString);
                        }
                        foreach (DemandMessage demand in journal.DemandsForSameDirection)
                        {
                            comm.Send(acceptArray, demand.SenderRank, MSG_ACCEPT);
                            //Console.WriteLine($"Proces {journal.shipRank}: po wyjściu wysłałem procesowi {demand.SenderRank} ACCEPT do kanału {demand.Canal} (przeciwny kierunek).");
                            string logString = $"Proces {journal.shipRank}: wysyłana zgoda ma następujące wartości pól - Ranga: {accept.SenderRank}, Zajętość: {accept.CurrentOccupancy}, Zegar: {accept.LogicalClock}, Leaving counters: ";
                            foreach (int process in accept.LeavingCounters)
                            {
                                logString += $"{process} ";
                            }
                            //Console.WriteLine(logString);
                        }
                        journal.DemandsForOppositeDirection.Clear();
                        journal.DemandsForSameDirection.Clear();

                        //Oznaczamy wyjście z kanału
                        journal.CanalOfInterest      = null;
                        journal.IsBlockingCanalEntry = false;

                        //Zmień kierunek
                        journal.SwitchDirection();
                    }
                    waitForCommunicationHandle.Set();
                }
            });
        }