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 ...
随机推荐
- 变量名解析:LEGB原则
# -*- coding: cp936 -*- #python 27 #xiaodeng #变量名解析:LEGB原则 ''' L-----local 局部名字空间 E-----enclosing 直接 ...
- 学习KNN
转:© 著作权归作者所有 by ido 什么是KNN算法呢?顾名思义,就是K-Nearest neighbors Algorithms的简称.我们可能都知道最近邻算法,它就是KNN算法在k=1时的特例 ...
- iOS-按钮单选与多选逻辑处理
概述 循环创建按钮, 进行按钮单选或者多选的操作. 详细 代码下载:http://www.demodashi.com/demo/10712.html 我们经常会有多行多列按钮的页面, 这个时候我们通常 ...
- C#编写的 8种初级+高级排序方法(转)
摘自:http://blog.csdn.net/mevin/article/details/6714520 程序代码: view plaincopy to clipboard using System ...
- SpringMVC中的Controller默认单例
众所周知,Servlet是单例的. 在struts中,Action是多例的,每一个请求都会new出来一个action来处理. 在Spring中,Controller默认是单例的,多个请求都会访问同一个 ...
- Python实现 K_Means聚类算法
使用 Python实现 K_Means聚类算法: 问题定义 聚类问题是数据挖掘的基本问题,它的本质是将n个数据对象划分为 k个聚类,以便使得所获得的聚类满足以下条件: 同一聚类中的数据对象相似度较高 ...
- SPFA 上手题 数 枚:
1, HDU 1548 A strange lift :http://acm.hdu.edu.cn/showproblem.php?pid=1548 这道题可以灰常巧妙的转换为一道最短路题目,对第i层 ...
- 高效开发 Android App 的 10 个建议
假如要Google Play上做一个最失败的案例,那最好的秘诀就是界面奇慢无比.耗电.耗内存.接下来就会得到用户的消极评论,最后名声也就臭了.即使你的应用设计精良.创意无限也没用. 耗电或者内存占用等 ...
- pythonl练习笔记——threading线程中的事件Event
1 事件Event 使用方法:e = threading.Event() Event对象主要用于线程间通信,确切地说是用于主线程控制其他线程的执行. Event事件提供了三个方法:wait等待.cle ...
- ant-jmeter批量脚本
<?xml version="1.0"?> <project name="autotest" default="all" ...