List和Queue使用过程中的纪录
业务需求: 发送特定的请求,根据返回的信息执行特定的事件。
目前的做法:把我的请求放入一个容器内,然后待到某一条件,就从这个容器把请求发送出去,等客户返回信息时,查询容器中对应请求中特定的事件。开始的时候我使用 List .其中遇到一些问题,纪录一下
1 namespace CollSecExp
2 {
3 class Program
4 {
5 static void Main(string[] args)
6 {
7 List<int> list = new List<int>();
8 for (int i = 0; i < 10; i++)
9 {
10 list.Add(i);
11 }
12
13 Thread t1 = new Thread(() =>
14 {
15 foreach (var item in list)
16 {
17 Console.WriteLine("t1.item:{0}", item);
18 Thread.Sleep(1000);
19 }
20 });
21 t1.Start();
22
23 Thread t2 = new Thread(() =>
24 {
25 Thread.Sleep(1000);
26 list.RemoveAt(1);
27 list.RemoveAt(3);
28 foreach (var item in list)
29 {
30 Console.WriteLine("t2.item:{0}", item);
31 }
32 });
33 t2.Start();
34 }
35 }
36 }运行会抛出InvalidOperationException异常,提示“集合已修改;可能无法执行枚举操作。”
这是因为,线程2移除index=1,3的元素导致集合被修改。使用加锁
1 namespace CollSecExp
2 {
3 class Program
4 {
5 static void Main(string[] args)
6 {
7 object sycObj = new object();
8 List<int> list = new List<int>();
9 for (int i = 0; i < 10; i++)
10 {
11 list.Add(i);
12 }
13
14 Thread t1 = new Thread(() =>
15 {
16 lock (sycObj)
17 {
18 foreach (var item in list)
19 {
20 Console.WriteLine("t1.item:{0}", item);
21 Thread.Sleep(1000);
22 }
23 }
24 });
25 t1.Start();
26
27 Thread t2 = new Thread(() =>
28 {
29 Thread.Sleep(1000);
30 lock (sycObj)
31 {
32 list.RemoveAt(1);
33 list.RemoveAt(3);
34 foreach (var item in list)
35 {
36 Console.WriteLine("t2.item:{0}", item);
37 }
38 }
39 });
40 t2.Start();
41 }
42 }
43 }加锁就可以解决了。
后来使用了想起了对于请求,我们可以使用队列,最简单的请求Queue如下
1 static void Main(string[] args)
2 {
3 int count = 0;
4 Queue<int> queue = new Queue<int>();
5 Task.Factory.StartNew(() =>
6 {
7 while (true)
8 {
9 Thread.Sleep(3000);
10 Console.WriteLine("生产的元素是: " + count);
11 queue.Enqueue(count);
12 count++;
13
14 }
15
16 });
17
18 ;
19 Task.Factory.StartNew(() =>
20 {
21 while (true)
22 {
23 if (queue.Count > 0)
24 {
25 int value = queue.Dequeue();
26 Console.WriteLine("worker1 " + ": 消费的元素是: " + value);
27 }
28 }
29
30 });
31
32 Task.Factory.StartNew(() =>
33 {
34 while (true)
35 {
36 if (queue.Count > 0)
37 {
38 int value = queue.Dequeue();
39 Console.WriteLine(Thread.CurrentThread + " : 消费的元素是: " + value);
40 }
41 }
42
43 });
44
45
46 Console.ReadKey();
47
48 }由于没有加锁或是其他机制,那么很容易出错,于是改进了版本。
1 static void Main(string[] args)
2 {
3 int count = 0;
4 var queue = new ConcurrentQueue<int>();
5 Task.Factory.StartNew(() =>
6 {
7 while (true)
8 {
9 Thread.Sleep(1000);
10 Console.WriteLine("生产的元素是: " + count);
11 queue.Enqueue(count);
12 count++;
13
14 }
15
16 });
17
18 ;
19 Task.Factory.StartNew(() =>
20 {
21 while (true)
22 {
23
24 int value;
25 if (queue.TryDequeue(out value))
26 {
27 Console.WriteLine("worker1 " + ": 消费的元素是: " + value);
28 }
29
30 }
31
32 });
33
34 Task.Factory.StartNew(() =>
35 {
36 while (true)
37 {
38 int value;
39 if (queue.TryDequeue(out value))
40 {
41 Console.WriteLine("worker2 " + " : 消费的元素是: " + value);
42 }
43 }
44
45 });
执行这段代码,可以工作,但是有点不太优雅,能不能不要去判断集合是否为空?集合当自己没有元素的时候自己Block一下可以吗?答案当然是可以的,使用BlockingCollection即可:
1 static void Main(string[] args)
2 {
3 int count = 0;
4 var queue = new BlockingCollection<int>();
5 var product = Task.Factory.StartNew(() =>
6 {
7 for (int i = 20 - 1; i >= 0; i--)
8 {
9 Console.WriteLine("生产的元素是: " + count);
10 queue.Add(count);
11 count++;
12 }
13
14 });
15
16
17 var consumer1 = Task.Factory.StartNew(() =>
18 {
19 foreach (int value in queue.GetConsumingEnumerable())
20 {
21 Console.WriteLine("worker1 " + ": 消费的元素是: " + value);
22
23 }
24
25 });
26
27 var consumer2 = Task.Factory.StartNew(() =>
28 {
29 foreach (int value in queue.GetConsumingEnumerable())
30 {
31 if (value % 2 == 0)
32 {
33 Console.WriteLine("worker2 " + " : 消费的元素是: " + value);
34 }
35 else
36 {
37 queue.Add(value);
38 }
39 }
40 });
41 Task.WaitAny(product, consumer2, consumer1);
42 Console.ReadKey();
43 }
当我需要控制Queue停止反复遍历获取queue是否存在元素时,可以使用如下方法,同时在构造方法中可以指定队列的大小
1 blockingCollection.CompleteAdding();
参考文章:
C#的变迁史 - C# 4.0 之线程安全集合篇
List和Queue使用过程中的纪录的更多相关文章
- 使用beanstalkd实现定制化持续集成过程中pipeline
持续集成是一种项目管理和流程模型,依赖于团队中各个角色的配合.各个角色的意识和配合不是一朝一夕能练就的,我们的工作只是提供一种方案和能力,这就是持续集成能力的服务化.而在做持续集成能力服务化的过程中, ...
- zabbix 3.0.3 (nginx)安装过程中的问题排错记录
特殊注明:安装zabbix 2.4.8和2.4.6遇到2个问题,如下:找了很多解决办法,实在无解,只能换版本,尝试换(2.2.2正常 | 3.0.3正常)都正常,最后决定换3.0.3 1.Error ...
- 最新cocoapods安装流程,安装过程中遇到的问题及解决方法
最近重新安装了一次cocoapods,参考的安装流程:http://blog.csdn.net/showhilllee/article/details/38398119/ 但是现在的cocoapods ...
- ios逆向过程中lldb调试技巧
在ios逆向过程中,善于运用lldb,会给逆向带来很大的方便 一般的命令: 1.image list -o -f 看看各个模块在内存中的基址 2.register read r0 读取寄存器r0的 ...
- 使用 VSTS 进行 CI 的过程中,无法识别 .NET Core 2.x 的情况处理
大概是由于 .NET Core 2.1 还没有正式发布,使用 VSTS 进行持续集成(CI)的过程中,自动 Build 的环节无法识别 .NET Core 2.1 的框架,查看日志会提示如下错误: V ...
- sharepoint环境安装过程中几点需要注意的地方
写在前面 上篇文章也说明了,在安装sharepoint环境的时候,确实吃了不少苦头,这里纪录一下安装过程中遇到的几个问题. 安装环境 windows server 2012 r2 standard x ...
- QTcpSocket使用过程中的一些问题记录
目前,在将原来C的socket通讯改为使用Qt类库QTcpSocket通讯,在修改过程中遇到不少问题,在此将问题一并记录,以备后面使用. 采用的通讯方式:QTimer定时器.QThread多线程和QT ...
- CASE:DB shutdown/open 过程中发生异常导致JOB不能自动执行
CASE:DB shutdown/open 过程中发生异常导致JOB不能自动执行 现象: 一个DB中的所有JOB在3月25日之后就不再自动运行,查询DBA_JOBS,发现LAST_DATE定格在3月2 ...
- 在对listctrl的控件进行重载的过程中,GetHeaderCtrl()返回NULL的问题
先谈谈我的问题吧! 在使用listctrl的过程中,我需要在列表头部添加checkbox,实现全选的功能. 经过网上资料的罗列,我找到了一个demo,使用的重绘的方法,在使用的过程中,我发现我的列表头 ...
随机推荐
- powshel 控制目录文件权限
for($file=[IO.File]::OpenText("C:\Users\Administrator\Desktop\user_list.txt") ; !($file.En ...
- OCP最新题库收集,新版052考题及答案整理-19
19.Which is true about invalid PL/SQL objects? A) They are automatically recompiled against the new ...
- [BZOJ]4650 优秀的拆分(Noi2016)(哈希+二分)
传送门 题解 听说大佬们这题都是用SA秒掉的 然而SA的时间复杂度的确很优秀,缺点就是看不太懂…… 然后发现一位大佬用哈希华丽的过了此题,而且讲的特别清楚->这里 我们只要考虑以每一个点结尾 ...
- NSCharacterSet 关于字符串编码
此文转自:http://nshipster.cn/nscharacterset/ 只为个人为了查找问题方便才复制过来的....... 正如之前提前过的,基础类库(Foundation)拥有最好的.功能 ...
- protobuf高效传输对比json gizp等等
https://blog.csdn.net/u013929284/article/details/72582215 利用Protocol Buffers可以很好的解决JSON数据在传输方面的不足,它是 ...
- Ionic无法通过npm安装解决方案
http://www.jianshu.com/p/5a99334eb62d 一般从 node.js官网下载安装完之后,npm也会同时安装完. 如果通过 $ npm install -g cordova ...
- js 正则表达式(reg)
一.RegExp对象方法: 1.exec() 检索字符串中指定的值,并返回值(找不到返回null) 效果: <textarea name="content" id=&qu ...
- Django---错误
ValueError: Dependency on app with no migrations: users 先 python manage.py makemigration 后 python ma ...
- Unity 行为树-中断机制
一.中断类型 设置了中断之后,行为树会检测执行过的子条件节点,当条件节点的状态发生变化时,会中断正在执行的Running节点,转而立即执行该条件节点. 行为树的打断类型有4种: None Self L ...
- python学习,day2:字典
字典的增删改查 # coding=utf-8 # Author: RyAn Bi info = { 'stu1101':'Tenglan Wu', 'stu1102':'longze Luola', ...