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,使用的重绘的方法,在使用的过程中,我发现我的列表头 ...
随机推荐
- OCP题库变了,2018年052新题库-29题
29.In one of your databases: * The database default tablespace is EXAMPLE. * Deferred_segment_creati ...
- 在Java中如何优雅地判空
判空灾难 作为搬砖党的一族们,我们对判空一定再熟悉不过了,不要跟我说你很少进行判空,除非你喜欢NullPointerException. 不过NullPointerException对于很多猿们来 ...
- 吴裕雄 python 机器学习——高斯贝叶斯分类器GaussianNB
import matplotlib.pyplot as plt from sklearn import datasets,naive_bayes from sklearn.model_selectio ...
- MyBatis框架流程
Hibernate与Mybatis的本质区别和应用场景 Hibernate:标准的ORM框架,不需要写SQL语句,但是优化和修改SQL语句比较难. 应用于需求变化固定的中小型的项目,例如后台管理系统. ...
- C++默认构造函数的问题
C++ defaul construct :缺省构造函数(默认构造函数) 定义:第一种 构造函数没有参数,即是 A()形式的 第二种 构造函数的全部参数由缺省值提供,A(int a=0,int ...
- jquer 使用原生DOM对象
js中使document.getElementById("ID"); Jquery中可以使用$("#id") 或者$("#id").get( ...
- 虚拟机上使用 opecnv 读取USB摄像头无法显示
使用opecv读取USB摄像头时候,无法显示图像. 设置 首先查看虚拟机Ubuntu检测摄像头是否已正常插入: ls /dev/video* 结果为: 设置虚拟机USB属性: USB的兼容性设置为US ...
- 虚拟立方体调用非共享维度的时候需要指定cubeName,否则Schema无效
但是,即使把非共享维度放上去,会出现一种情况. 一旦放入资产负债的非公共维度进去后,报表的度量值只能出现资产负债的度量值,不能出现损益的度量值了!
- stark - 1 ⇲一些理念
⒈.django项目启动时,自定义执行某个py文件. 在任意的app的apps.py中的Config类中定义ready方法,并调用autodiscover_modules from django.ap ...
- cuda9.0 中不存在libnppi.so
编译一个caffe版本,报错找不到 -lnppi 发现使用打是cuda9.0, 但是cuda9.0 中不存在libnppi.so. 只好换成cuda8.0.