队列简单使用

队列说明

什么是队列?我想学习过数据结构应该很清楚,如果没有仔细了解,只要记住队列是一个先进先出的列表即可,列表中可以是线程,可以是预备执行的函数的入口,可以是地址,可以是数据,在C#中,Queue 类可以实现队列,这一个类可以简单的让我们完成数据的插入和获取,可以在便利性这一块十分出众的。

目标

在这一步,我们将建立一个存储String数据的队列,为了实用队列能够用多线程的方式来插入,后台将有一个长时间运行的线程来不断将数据从队列取出并执行我们编写的内容。因此需要规划多线程之间资源冲突如何避免的措施。

发环境:VisualStudio 2017和 .NET 4.5.2

函数功能与实施

首先,需要定义下存储的数据,这里设置的是结构体,主要存储的内容为字符串

1
2
3
4
5
6
7
8
9
struct bbchecklist
{

public string stand_title;
public string fail_title;
public string success_title;
public int num;

}

并且事先定义好显示数据的函数

1
2
3
4
5
static bool DispalyData(bbchecklist bb)
{
System.Console.WriteLine("{0}:{1} {2} {3}", bb.num, bb.stand_title, bb.success_title, bb.fail_title);
return true;
}

再来是设置一个Queue类,以进行调用,实例化后,这就是我们存储和取出数据的位置,有点像List类

1
static Queue<bbchecklist> _tasks = new Queue<bbchecklist>(); 

如何加数据到刚刚设置好的队列?方法很简单,与List的操作是一致的,使用Queue类的Enqueue函数来添加,这里定义一个Enqueue函数来添加数据到队列,可以看到有一个object类的锁,它的作用就是防止冲突

1
readonly static object _locker = new object();
1
2
3
4
5
6
7
8
9
10
11
12
13
static bool EnqueuelTask(int num ,string stdStr,string failStr,string succeedStr)
{
lock(_locker)
{
bbchecklist newitem =new bbchecklist();
newitem.stand_title = stdStr;
newitem.fail_title = failStr;
newitem.num = num;
newitem.success_title = succeedStr;
_tasks.Enqueue(newitem);
}
return true;
}

然后,定义一下输出这个队列中的内容的线程。

线程的逻辑是,在运行时候不断的去取出队列中末尾的数据并读取,当读取的数据不为空的时候,就会等待1200ms然后再次循环执行,当队列为空亦或是已经没有可以继续执行的项目的时候的时候,等待信号。

因此我们要实例化线程,还需要实例化信号,EventWaitHandle可以让我们的线程处于等待的状态,当有新的通知的时候再运行,这样就不用每间隔一段时间去查询是否有新的任务,上面所说的1200ms是执行间隔时间

1
2
static Thread _worker;
static EventWaitHandle _wh = new AutoResetEvent(false);

用于取出数据并打印出来的线程实现如下,当读取数据时候,上锁,防止此时写入数据,当线程读取到-1时候,线程退出程序结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static void Work()
{
while(true)
{
bbchecklist title;
lock ( _locker) //锁,用来保护数据读写不会冲突
{
if(_tasks.Count > 0) //队列中剩余的数据
{
title = _tasks.Dequeue(); //去取得数据
DispalyData(title);
if (title.num == -1)
{
System.Console.WriteLine("---Queue Over---");
return;
}
}
}
if (title.fail_title != null) //任务不为空
{
Thread.Sleep(1200);
}
else
{
_wh.WaitOne();
}
}
}

整个程序的所有代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace QueueApp
{
class Program
{
struct bbchecklist
{

public string stand_title;
public string fail_title;
public string success_title;
public int num;

}
struct FactorySet
{
static int FPLHP25;
static int FPLHP40;
}
struct TTCDM //时间法测试数据项目
{
static int PLHP40;
static int PLHP25;
public double IHP;
public int CCDT40;
public int CCDT25;
public int DIW;
public int v40s;
public int v25s;
public int v40e;
public int v25e;
}
struct PTCDM //能量法测试数据项目
{
public int ACDT70;
public int ACDT60;
public int ACDT50;
public int ACDT40;
public int ACDT30;
public int ACDT25;
public int ACDT20;
}

static Queue<bbchecklist> _tasks = new Queue<bbchecklist>(); //队列
readonly static object _locker = new object(); //使用一个锁来保护_task的访问
static EventWaitHandle _wh = new AutoResetEvent(false); //通知Work线程的信号
static Thread _worker;

static void Main(string[] args)
{
_worker = new Thread(Work);
_worker.Start();

SetQueueData();
Dispose();
}
/// <summary>
/// 任务执行线程
/// </summary>
static void Work()
{
while(true)
{
bbchecklist title=new bbchecklist();
lock ( _locker)
{
if(_tasks.Count > 0)
{
title = _tasks.Dequeue();
DispalyData(title);
if (title.num == -1)
{
System.Console.WriteLine("---Queue Over---");
return;
}
}
}
if (title.fail_title != null) //任务不为空
{
Thread.Sleep(1200);
}
else
{
_wh.WaitOne();
}
}
}
/// <summary>
/// 插入队列
/// </summary>
/// <param name="num"></param>
/// <param name="stdStr">一般提示语句</param>
/// <param name="failStr">失败提示语句</param>
/// <param name="succeedStr">成功提示语句</param>
static bool EnqueuelTask(int num ,string stdStr,string failStr,string succeedStr)
{
lock(_locker)
{
bbchecklist newitem =new bbchecklist();
newitem.stand_title = stdStr;
newitem.fail_title = failStr;
newitem.num = num;
newitem.success_title = succeedStr;
_tasks.Enqueue(newitem);
}
return true;
}
/// <summary>
/// 设置队列预置的数据
/// </summary>
/// <param name="num"></param>
/// <returns>设置成功true,设置失败false</returns>
static bool SetQueueData()
{
EnqueuelTask(0, "测功机预热中..", "预热失败,按F8继续", "测功机预热完成按F8继续");
EnqueuelTask(1, "正在进行时间法滑行测试..", "测试失败!按F8继续进行能量法测试", "测试已通过!按F8继续");
EnqueuelTask(2, "正在进行能量法滑行测试..", "能量法测试失败!", "能量法测试成功!");
return true;
}
/// <summary>
/// 停止线程的运行并释放所有的资源
/// </summary>
static void Dispose()
{
EnqueuelTask(-1, "正在结束测试..", "结束测试未完成", "测试已结束");//加入最后的
_worker.Join();//阻止调用线程
_wh.Close();//释放信号
}
/// <summary>
///
/// </summary>
static bool DispalyData(bbchecklist bb)
{
System.Console.WriteLine("{0}:{1} {2} {3}", bb.num, bb.stand_title, bb.success_title, bb.fail_title);
return true;
}


}
}

整个软件最终运行的结果


相关链接(侵删)

  1. C# 二维数组(2d Array)解析

=================我是分割线=================

欢迎到公众号来唠嗑: