多线程环境下,一个List<T>集合,不对进行它删除和修改操作,只对它做添加和读取操作.
譬如:fn1,fn2,fn3这三个函数对这个集合进行添加操作,fn4,fn5这两个函数对它进行读取操作,这五个函数并行运行,代码中不用lock这样会不会有问题?
譬如:fn1,fn2,fn3这三个函数对这个集合进行添加操作,fn4,fn5这两个函数对它进行读取操作,这五个函数并行运行,代码中不用lock这样会不会有问题?
调试欢乐多
并行查询,不用管锁
http://msdn.microsoft.com/zh-cn/library/6sh2ey19(v=vs.95).aspx最后一段:
线程安全:此类型的公共静态(在 Visual Basic 中为 Shared)成员是线程安全的。但不保证所有实例成员都是线程安全的。只要不修改该集合,List<T> 就可以同时支持多个阅读器。枚举整个集合本质上不是一个线程安全的过程。在枚举与一个或多个写访问竞争的罕见情况下,确保线程安全的唯一方法是在整个枚举期间锁定集合。若允许多个线程对集合执行读写操作,您必须实现自己的同步。
读取操作用下面代码: for(int i=0;i<items.Count;++i)
{
Console.WriteLine(items[i]);
}
有谁能指出我理解上的漏洞?
这种多线程读取的同一集合中的内容不是线程安全的,如果不加锁就会造成问题.你给出的代码不能解决在另外一个线程中Insert了元素的问题,不能保证读取的是正确结果,这就是线程不安全.不能保证读取的结果是正确的,这种代码能引入到项目中?例如
线程1在枚举 for(int i=0;i<items.Count;++i){... };
线程2在Insert: items.insert(10,XXX);能保证线程1枚举第十个元素的时候是什么值?如果不加锁,不能保证,可能是原来的第十个元素,也可能是后来Insert的.
对于多线程访问集合应该使用加锁机制,msdn上说了这种操作不是现场安全的,像你上面的代码 如果只针对添加和读取而且添加使用<List>.add() 方法应该能得到正确的结果,当时如果使用<List>.insert() 就会有问题。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;namespace MultiThread
{
class Program
{
static List<int> Itmes = new List<int>();
static int iCount = 0;
static void Main(string[] args)
{
Thread th1 = new Thread(new ThreadStart(Add));
Thread th2 = new Thread(new ThreadStart(Add));
Thread th3 = new Thread(new ThreadStart(Show));
th1.Start();
th2.Start();
th3.Start();
} static void Add()
{
while (Itmes.Count < 1000000)
{
for (int i = iCount; i < iCount + 1000; i++)
{
Itmes.Add(i);
Thread.Sleep(50);
}
iCount = iCount + 1000;
}
Thread.CurrentThread.Abort();
} static void Show()
{
while (Itmes.Count < 1000000)
{
for (int i = iCount; i < Itmes.Count; i++)
{
Console.WriteLine(Itmes[i].ToString());
}
}
Thread.CurrentThread.Abort();
}
}
}
//static int iCount = 0;
static void Main(string[] args)
{
Thread th1 = new Thread(new ThreadStart(Add));
Thread th2 = new Thread(new ThreadStart(Add));
Thread th3 = new Thread(new ThreadStart(Show)); th1.IsBackground = true;
th2.IsBackground = true;
th3.IsBackground = true; th1.Start();
th2.Start();
th3.Start();
// Console.WriteLine("按回车键退出程序");
Console.ReadLine();
//th1和th2结束后,这时的Items.Count属性值是2000000,不会出现不一致的情况
} static void Add()
{
//while (Itmes.Count < 1000000)
//{
// for (int i = iCount; i < iCount + 1000; i++)
// {
// Itmes.Add(i);
// // Thread.Sleep(50);
// }
// iCount = iCount + 1000;
//}
//Thread.CurrentThread.Abort(); Random r = new Random();
for (int i = 0; i < 100000; ++i)
{
Itmes.Add(r.Next(int.MaxValue));
Thread.Sleep(20);
}
} static void Show()
{
//while (Itmes.Count < 1000000)
//{
// for (int i = iCount; i < Itmes.Count; i++)
// {
// Console.WriteLine(Itmes[i].ToString());
// }
//}
//Thread.CurrentThread.Abort(); while(true)
for (int i = 0; i < Itmes.Count; ++i)
{
Console.WriteLine(Itmes[i]);
}
}
for (int i = 0; i < Itmes.Count; ++i)
{
Console.WriteLine(Itmes[i]);
}
你需要每次都在从 0 ~ Items.Count 进行显示.?如果是,我无话可说了,再讨论下去也没有意义了.