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();
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#中一道关于线程同步的练习题——模拟多窗口售票的更多相关文章
- C#中一道关于多线程的基础练习题——模拟仓库存销过程
题目:模拟生产.入库.销售(50分) 假设某企业自产.自存.自销,需要将工厂生产的各类产品不定时的运到仓库,与此同时,需要将仓库中的货物运往超市和商场中进行销售,请编写一个程序模拟此过程(主要是存取这 ...
- 操作系统中的进程同步与Window中利用内核对象进行线程同步的关系
操作系统中为了解决进程间同步问题提出了用信号量机制,信号量可分为四种类型分别是互斥型信号量,记录型信号量,AND型信号量,信号量集. 互斥型信号量 互斥型信号量是资源数量为1的特殊的记录型信号量.表示 ...
- Java多线程02(线程安全、线程同步、等待唤醒机制)
Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...
- [C# 线程处理系列]专题四:线程同步
目录: 一.线程同步概述 二.线程同步的使用 三 .总结 一.线程同步概述 前面的文章都是讲创建多线程来实现让我们能够更好的响应应用程序,然而当我们创建了多个线程时,就存在多个线程同时访问一个共享的资 ...
- C#线程学习笔记五:线程同步--事件构造
本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/23/Event_Constructor.html,记录一下学习过程以备后续查用. 前面讲的线 ...
- java基础(27):线程安全、线程同步、等待唤醒机制
1. 多线程 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. 我们通过一个案例,演示线程 ...
- 第十七节:Runnable创建线程,Thread创建线程,唤醒线程和计数器多线程,线程同步与等待
Runnable创建线程 public class RunnableDemo implements Runnable{ @Override public void run(){ int i = 1; ...
- java ->多线程_线程同步、死锁、等待唤醒机制
线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. l 我们通过一个案例,演示线 ...
- Linux 系统编程 学习:11-线程:线程同步
Linux 系统编程 学习:11-线程:线程同步 背景 上一讲 我们介绍了线程的属性 有关设置.这一讲我们来看线程之间是如何同步的. 额外安装有关的man手册: sudo apt-get instal ...
随机推荐
- SettingsEditplus
迁移时间:2017年5月20日10:51:51Author:Marydon官网下载 http://www.editplus.com/设置一 1.修改字体大小及背景色 首选项-->Genera ...
- webservice系统学习笔记9-使用契约优先的方式的一个服务端demo(隐式传Header信息)
服务器端: 1.编写wsdl文件 <?xml version="1.0" encoding="UTF-8" standalone="no&quo ...
- Web服务器(容器)请求常见的错误及其解决方法
首先我们来看看容器如何找到service()方法?(1)当在浏览器中输入 http://localhost:8080/firstweb/sayHi 这个地址后,容器是如何找到 HelloServlet ...
- permission denied make_sock could not bind to address 81问题解决
在apache中绑定非http标准端口时,一直出现如下的错误提示: [root@localhost ~]# /etc/init.d/httpd start Starting httpd: (13)Pe ...
- MySQL5.7 二进制源码包安装
一般平时安装MySQL都是源码包安装的,但是由于它的编译需要很长的时间,所以建议安装二进制免编译包.可以到MySQL官方网站去下载,也可以到comsenz官方网站下载,还有各大镜像站下载. 下载安装包 ...
- C#编写的 8种初级+高级排序方法(转)
摘自:http://blog.csdn.net/mevin/article/details/6714520 程序代码: view plaincopy to clipboard using System ...
- 【转载】@RequestMapping的分类
@RequestMapping的分类 类级别的和方法级别的@RequestMapping的几种形式: @RequestMapping(method = RequestMethod.GET) @Req ...
- mysql中字符集和排序规则说明
数据库需要适应各种语言和字符就需要支持不同的字符集(Character Set),每种字符集也有各自的排序规则(Collation). 一.字符集 字符集,即用于定义字符在数据库中的编码的集合. 常见 ...
- HDUOJ---Piggy-Bank
Piggy-Bank Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- 【js与jquery】jquery循环滚动新闻
2.html代码: <h3>最新动态</h3> <div class="scrollNews" > <ul> <li>& ...