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; } } }
本次修改了售罄方法和入口方法(橙色字体),运行结果如下:
欢迎继续提出意见!谢谢大家~
本文来自博客园,作者:天外归云,转载请注明原文链接:https://www.cnblogs.com/LanTianYou/p/4578776.html