• C#中一道关于线程同步的练习题——模拟多窗口售票


    题目:模拟窗口卖票,四个窗口同时对外开放售票,需要按顺序售出。

    要求:输出每一张票的售出时间和售出窗口,不能出现票未售出或者被售出多次的情况。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    using System.IO;
    using System.Reflection;
    using System.Diagnostics;
    
    namespace SellTicketsSynchronously
    {
        class Program
        {
            //入口
            static void Main(string[] args)
            {
                Ticket tc = new Ticket(10);
                Thread sellWindowA = new Thread(new ParameterizedThreadStart(SellTicket));
                Thread sellWindowB = new Thread(new ParameterizedThreadStart(SellTicket));
                Thread sellWindowC = new Thread(new ParameterizedThreadStart(SellTicket));
                Thread sellWindowD = new Thread(new ParameterizedThreadStart(SellTicket));
                sellWindowA.Name = "Window A";
                sellWindowB.Name = "Window B";
                sellWindowC.Name = "Window C";
                sellWindowD.Name = "Window D";
                sellWindowA.Start(tc);
                sellWindowB.Start(tc);
                sellWindowC.Start(tc);
                sellWindowD.Start(tc);
                sellWindowA.Join();
                sellWindowB.Join();
                sellWindowC.Join();
                sellWindowD.Join();
                Console.WriteLine("Tickets has been sold out. Press any key to quit:");
                Console.ReadLine();
            }
            //卖票方法
            public static void SellTicket(object obj) 
            {
                Ticket ticket = obj as Ticket;
                while (ticket.NumOfTickets>0)
                {
                    lock (ticket)
                    {
                        if (ticket.NumOfTickets > 0)
                        {
                            try
                            {
                                ticket.NumOfTickets--;
                                Console.WriteLine( DateTime.Now.ToString()+":"+Thread.CurrentThread.Name + " sells a ticket, " + ticket.NumOfTickets + " tickets left.");
                            }
                            catch (Exception ex)
                            {
                                WriteLog(ex);
                            }
                        }
                    }
                    Random random = new Random();
                    Thread.Sleep(random.Next(100,500));
                } 
            }
            //打log方法
            private static void WriteLog(Exception ex)
            {
                string logUrl = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\SellTicketslog.txt";
                if (File.Exists(@logUrl))
                {
                    using (FileStream fs = new FileStream(logUrl, FileMode.Append))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                        {
                            try
                            {
                                sw.Write(ex);
                            }
                            catch (Exception ex1)
                            {
                                WriteLog(ex1);
                            }
                            finally
                            {
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }
                }
                else
                {
                    using (FileStream fs = new FileStream(logUrl, FileMode.CreateNew))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                        {
                            try
                            {
                                sw.Write(ex);
                            }
                            catch (Exception ex1)
                            {
                                WriteLog(ex1);
                            }
                            finally
                            {
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }
                }
            }
        }
        //票类
        class Ticket 
        {
            public int NumOfTickets { get; set; }
            public Ticket(int num) 
            {
                this.NumOfTickets = num;
            }
        }
    }

    运行结果:

    不知道这么写会不会有问题,求指点。

    ————————修改版——————————

    经过园友指点,我改用了Task写了这段代码,其间得到了园友的帮助,非常感谢!

    修改后的代码如下(蓝色字体为修改的部分):

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    using System.IO;
    using System.Reflection;
    using System.Diagnostics;
    
    namespace SellTicketsSynchronously
    {
        class Program
        {
            //入口
            static void Main(string[] args)
            {
                Ticket tc = new Ticket(10);
                WaitForAllSales(tc);
                Console.WriteLine("Tickets has been sold out. Press any key to quit:");
                Console.ReadLine();
            }
            //售罄方法
            private static void WaitForAllSales(Ticket tc) 
            {
                //创建一个Task类型的泛型list
                List<Task> tasks = new List<Task>();
                for (int i = 1; i <= 4; i++)
                {
                    //将所有的售票task存入list
                    tasks.Add(Task.Run(() => { SellTicket(string.Format("Window"+i), tc); }));
                }
                //等待所有的task都完成
                Task.WaitAll(tasks.ToArray());
            }
            //卖票方法
            public static void SellTicket(string windowName, object obj) 
            {
                string nameOfWindow = windowName;
                Ticket ticket = obj as Ticket;
                while (ticket.NumOfTickets > 0)
                {
                    lock (ticket)
                    {
                        if (ticket.NumOfTickets > 0)
                        {
                            try
                            {
                                ticket.NumOfTickets--;
                                Console.WriteLine(DateTime.Now.ToString() + ":" + nameOfWindow + " sells a ticket, " + ticket.NumOfTickets + " tickets left.");
                            }
                            catch (Exception ex)
                            {
                                WriteLog(ex);
                            }
                        }
                    }
                    Random random = new Random();
                    Thread.Sleep(random.Next(100,500));
                }
            }
            //打log方法
            private static void WriteLog(Exception ex)
            {
                string logUrl = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\SellTicketslog.txt";
                if (File.Exists(@logUrl))
                {
                    using (FileStream fs = new FileStream(logUrl, FileMode.Append))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                        {
                            try
                            {
                                sw.Write(ex);
                            }
                            catch (Exception ex1)
                            {
                                WriteLog(ex1);
                            }
                            finally
                            {
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }
                }
                else
                {
                    using (FileStream fs = new FileStream(logUrl, FileMode.CreateNew))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                        {
                            try
                            {
                                sw.Write(ex);
                            }
                            catch (Exception ex1)
                            {
                                WriteLog(ex1);
                            }
                            finally
                            {
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }
                }
            }
        }
        //票类
        class Ticket 
        {
            public int NumOfTickets { get; set; }
            public Ticket(int num) 
            {
                this.NumOfTickets = num;
            }
        }
    }

    运行结果:

    欢迎大家发散思维,继续提出宝贵意见!:)

     ------------------------------------------------------------------------------------------------------------

    经过一位朋友细心的发现,上面这个程序逻辑是有问题的,一直都是售票窗口5在售票,修改后的代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    using System.IO;
    using System.Reflection;
    using System.Diagnostics;
    
    namespace SellTicketsSynchronously
    {
        class Program
        {
            //入口
            static void Main(string[] args)
            {
                Ticket tc = new Ticket(20);
                WaitForAllSales(tc);       
                Console.ReadLine();
            }
            //售罄方法
            private static void WaitForAllSales(Ticket tc) 
            {
                //创建一个Task类型的泛型list
                List<Task> tasks = new List<Task>();
                System.Random ran = new Random();
                while (tc.NumOfTickets > 0)
                {
                    int i = ran.Next(1,6);
                    //将所有的售票task存入list
                    tasks.Add(Task.Run(() => { SellTicket(string.Format("Window" + i), tc); }));
                    Task.WaitAll(tasks.ToArray());
                }
                Console.WriteLine("Tickets has been sold out. Press any key to quit:");
            }
            //卖票方法
            public static void SellTicket(string windowName, object obj) 
            {
                string nameOfWindow = windowName;
                Ticket ticket = obj as Ticket;
                lock (ticket)
                {
                    if (ticket.NumOfTickets > 0)
                    {
                        try
                        {
                            ticket.NumOfTickets--;
                            Console.WriteLine(DateTime.Now.ToString() + ":" + nameOfWindow + " sells a ticket, " + ticket.NumOfTickets + " tickets left.");
                        }
                        catch (Exception ex)
                        {
                            WriteLog(ex);
                        }
                    }
                    Random random = new Random();
                    Thread.Sleep(random.Next(100,500));
                }
            }
            //打log方法
            private static void WriteLog(Exception ex)
            {
                string logUrl = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\SellTicketslog.txt";
                if (File.Exists(@logUrl))
                {
                    using (FileStream fs = new FileStream(logUrl, FileMode.Append))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                        {
                            try
                            {
                                sw.Write(ex);
                            }
                            catch (Exception ex1)
                            {
                                WriteLog(ex1);
                            }
                            finally
                            {
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }
                }
                else
                {
                    using (FileStream fs = new FileStream(logUrl, FileMode.CreateNew))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                        {
                            try
                            {
                                sw.Write(ex);
                            }
                            catch (Exception ex1)
                            {
                                WriteLog(ex1);
                            }
                            finally
                            {
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }
                }
            }
        }
        //票类
        class Ticket 
        {
            public int NumOfTickets { get; set; }
            public Ticket(int num) 
            {
                this.NumOfTickets = num;
            }
        }
    }

    本次修改了售罄方法和入口方法(橙色字体),运行结果如下:

    欢迎继续提出意见!谢谢大家~

  • 相关阅读:
    关于联想笔记本ThinkPad E470 没有外音 插耳机却有声音的解决办法
    Win10无法启动软件提示MSVCP110.dll丢失
    POJ-3984 迷宫问题(BFS找最短路径并保存)
    转圈游戏(简单的快速幂)
    统计一个整数的二进制中1的个数(暴力)
    手写哈希(实现简单的加数、查询)
    CodeForces
    L2-2 社交集群 (25 分)(一个写挫的并查集)
    7-4 交换二叉树中每个结点的左孩子和右孩子 (20 分)
    7-3 堆中的路径 (25 分)
  • 原文地址:https://www.cnblogs.com/LanTianYou/p/4578776.html
Copyright © 2020-2023  润新知