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

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

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();
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>)
{
lock (ticket)
{
if (ticket.NumOfTickets > )
{
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(,));
}
}
//打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 > )
{
lock (ticket)
{
if (ticket.NumOfTickets > )
{
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(,));
}
}
//打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 > )
{
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(,));
}
}
//打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;
}
}
}

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

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

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

  1. C#中一道关于多线程的基础练习题——模拟仓库存销过程

    题目:模拟生产.入库.销售(50分) 假设某企业自产.自存.自销,需要将工厂生产的各类产品不定时的运到仓库,与此同时,需要将仓库中的货物运往超市和商场中进行销售,请编写一个程序模拟此过程(主要是存取这 ...

  2. 操作系统中的进程同步与Window中利用内核对象进行线程同步的关系

    操作系统中为了解决进程间同步问题提出了用信号量机制,信号量可分为四种类型分别是互斥型信号量,记录型信号量,AND型信号量,信号量集. 互斥型信号量 互斥型信号量是资源数量为1的特殊的记录型信号量.表示 ...

  3. Java多线程02(线程安全、线程同步、等待唤醒机制)

    Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...

  4. [C# 线程处理系列]专题四:线程同步

    目录: 一.线程同步概述 二.线程同步的使用 三 .总结 一.线程同步概述 前面的文章都是讲创建多线程来实现让我们能够更好的响应应用程序,然而当我们创建了多个线程时,就存在多个线程同时访问一个共享的资 ...

  5. C#线程学习笔记五:线程同步--事件构造

    本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/23/Event_Constructor.html,记录一下学习过程以备后续查用. 前面讲的线 ...

  6. java基础(27):线程安全、线程同步、等待唤醒机制

    1. 多线程 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. 我们通过一个案例,演示线程 ...

  7. 第十七节:Runnable创建线程,Thread创建线程,唤醒线程和计数器多线程,线程同步与等待

    Runnable创建线程 public class RunnableDemo implements Runnable{ @Override public void run(){ int i = 1; ...

  8. java ->多线程_线程同步、死锁、等待唤醒机制

    线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. l  我们通过一个案例,演示线 ...

  9. Linux 系统编程 学习:11-线程:线程同步

    Linux 系统编程 学习:11-线程:线程同步 背景 上一讲 我们介绍了线程的属性 有关设置.这一讲我们来看线程之间是如何同步的. 额外安装有关的man手册: sudo apt-get instal ...

随机推荐

  1. HTTP所承载的货物(图像、文本、软件等)要满足的条件

    HTTP所承载的货物(图像.文本.软件等)要满足的条件: •可以被正确识别 通过Content-Type 首部说明媒体格式,Content-Language 说明语言,以便浏览器和其他客户端能正确处理 ...

  2. python实现的电影票房数据可视化

    代码地址如下:http://www.demodashi.com/demo/14275.html 详细说明: Tushare是一个免费.开源的python财经数据接口包.主要实现对股票等金融数据从数据采 ...

  3. Android HandlerThread详解

    概述 Android HandlerThread使用,自带Looper消息循环的快捷类. 详细 代码下载:http://www.demodashi.com/demo/10628.html 原文地址: ...

  4. PHP原生实现,校验微信公众号||小程序服务器地址

    1.原生的.php文件:  test.php <?php header('Content-type:text'); define("TOKEN", "weixin& ...

  5. JavaScript中的闭包(closure)

    闭包的特性 1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃圾回收机制回收  闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露,主要用于私有的方法和变 ...

  6. PHP-PHP.INI常用配置详解

    variables_order: 假如为'GPCS'表示系统在定义PHP预定义变量时的顺序是GET,POST,COOKIES,SERVER, 此时$_ENV为空数组, 只要把'E'添加到'GPCS'后 ...

  7. html导出图片

    有一个神奇的库:html2canvas. 这个库简洁优美,使用方便. 下面先看一个小demo,它需要用到一张图片:haha.jpg. <html> <head> <scr ...

  8. iOS设计模式:简单工厂模式

    1.简述 首先需要说明一下,简单工厂模式不属于23种GOF设计模式之一.它也称作静态工作方法模式,是工厂方法模式的特殊实现(也就是说工厂模式包含简单工厂模式).这里对简单工厂模式进行介绍,是为后面的工 ...

  9. 【LeetCode】22. Generate Parentheses (2 solutions)

    Generate Parentheses Given n pairs of parentheses, write a function to generate all combinations of ...

  10. PHP在微博优化中的“大显身手”

    新浪微博宋琦:PHP在微博优化中的“大显身手” 地址http://www.csdn.net/article/2013-09-04/2816820-sina