using System;
using System.Collections.Generic;
using System.Threading;

class Program
{
    static Stack<int> ints = new();
    static object sync = new();
    static Random rnd = new(); // Közös, egyszer példányosított Random

    // Ez jelzi a főszálnak, hogy "ébredj fel, mert történt valami!" (adat jött, vagy szál állt le)
    static AutoResetEvent auto = new(false);

    static int aktivSzalak = 2; // Nyomon követjük a futó szálakat

    static void Main(string[] args)
    {
        Thread t1 = new Thread(genNum);
        Thread t2 = new Thread(genNum);

        t1.Start();
        t2.Start();

        bool fut = true;

        while (fut)
        {
            // A főszál alszik, amíg valaki nem hívja meg az auto.Set()-et (NINCS aktív várakozás)
            auto.WaitOne();

            // Ha felébredt, addig szedjük ki az adatokat, amíg van a stackben
            while (true)
            {
                int kiirando = -1;
                bool vanAdat = false;
                bool kilepes = false;

                lock (sync)
                {
                    if (ints.Count > 0)
                    {
                        kiirando = ints.Pop();
                        vanAdat = true;
                    }
                    else if (aktivSzalak == 0)
                    {
                        // Ha a stack üres ÉS már egyik szál sem fut, akkor végeztünk
                        kilepes = true;
                    }
                }

                // A lassú I/O műveletet (Console) a lock-on kívül végezzük
                if (vanAdat)
                {
                    Console.WriteLine(kiirando);
                }
                else if (kilepes)
                {
                    fut = false;
                    break; // Kilépünk a belső ciklusból
                }
                else
                {
                    // A stack üres, de még futnak a szálak. 
                    // Megszakítjuk a belső ciklust, és újra visszamegyünk a WaitOne()-hoz aludni.
                    break;
                }
            }
        }

        Console.WriteLine("Feldolgozás vége.");
    }

    static void genNum()
    {
        while (true)
        {
            int n;
            lock (rnd)
            {
                n = rnd.Next(0, 101);
            }

            lock (sync)
            {
                ints.Push(n);
            }

            // Jelezzük a főszálnak, hogy új adat van
            auto.Set();

            if (n == 99)
            {
                break;
            }
        }

        lock (sync)
        {
            aktivSzalak--;
        }

        // KRITIKUS LÉPÉS: Amikor egy szál leáll, mindenképp ébresztőt kell fújni a főszálnak!
        // Különben előfordulhat, hogy a főszál örökre a WaitOne()-on ragad, ha pont kiürült a stack.
        auto.Set();
    }
}