C#只读列表线程同步
本文关键字:同步 线程 列表 只读 | 更新日期: 2023-09-27 18:26:46
我在这里所做的是在多个线程中通过for each和index方法导航只读列表。结果看起来是线程安全的,但我不相信。
有人能告诉下面的代码(从只读列表中读取)是否是线程安全的吗?如果是,为什么?
public class ThreadTest
{
readonly List<string> port;
public ThreadTest()
{
port = new List<string>() { "1", "2", "3", "4", "5", "6" };
}
private void Print()
{
foreach (var itm in port)
{
Thread.Sleep(50);
Console.WriteLine(itm+"----"+Thread.CurrentThread.ManagedThreadId);
}
}
private void Printi()
{
for(int i=0;i<5;i++)
{
Thread.Sleep(100);
Console.WriteLine(port[i] + "--iiiii--" + Thread.CurrentThread.ManagedThreadId);
}
}
public void StartThread()
{
Task[] tsks = new Task[10];
tsks[0] = new Task(Print);
tsks[1] = new Task(Print);
tsks[2] = new Task(Print);
tsks[3] = new Task(Print);
tsks[4] = new Task(Print);
tsks[5] = new Task(Printi);
tsks[6] = new Task(Printi);
tsks[7] = new Task(Printi);
tsks[8] = new Task(Printi);
tsks[9] = new Task(Printi);
foreach (var tsk in tsks)
{
tsk.Start();
}
Task.WaitAll(tsks);
}
}
class Program
{
static void Main(string[] args)
{
new ThreadTest().StartThread();
Console.ReadLine();
}
}
只有在没有写入程序的情况下,才认为多个线程从List<T>
的同一实例中读取是线程安全的。
线程安全
此类型的公共静态(在Visual Basic中为共享)成员是线程安全的。任何实例成员都不能保证是线程安全的。
对列表执行多个读取操作是安全的,但如果在读取集合时对其进行修改,则可能会出现问题。为确保线程安全,请在读取或写入操作期间锁定集合。要使多个线程能够访问集合进行读写,必须实现自己的同步。有关具有内置同步的集合,请参阅System.collections.Concurrent命名空间中的类。有关固有的线程安全替代方案,请参阅ImmutableList类。
重点在于我。
http://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.110).aspx
如果它没有被记录为线程安全的,那么不要认为它是线程安全的!
我将给你一个例子,说明为什么你不应该假设它,除非它被记录下来:
假设在内部,List是一个节点的LinkedList,每个节点都包含一个值为的字符串。方法Search(字符串值)必须遍历节点以查找该值是否存在。显然这里不存在线程安全问题。
但现在,出于性能优化的原因,假设List保留了一个内部数组,其中写入了最后搜索的值,这对于立即检查最常见的搜索值非常有用。
你看到我们在这里做了什么吗?现在,读取会更改列表的内部状态,并且突变不是线程安全的。
通常,数据结构不会在读取时发生突变,但除非有文档记录,否则您不能依赖它!
在这个列表使用的特殊情况下,msdn说,正如已经提到的:
对列表执行多个读取操作是安全的,但是如果在读取集合时对其进行了修改,则可能会出现问题。为确保线程安全,请在读取或写入期间锁定集合活动使集合能够由多个线程访问对于阅读和写作,您必须实现自己的同步。有关具有内置同步的集合,请参阅System.Collections.Concurrent命名空间。对于固有螺纹-安全或者,请参见ImmutableList类。
考虑到这一点,是的,您可以以线程安全的方式进行多次读取而不进行写入,但除非有文档记录,否则不要想当然。
如果你想只使用List进行读取,我建议你用一个只在列表上公开读取操作的类来包装它,这将确保没有代码意外地更改列表。
如果没有人更改列表,为什么它不是线程安全的?我在这里看到的唯一问题是,如果(你是超人)你按键的速度比线程读取列表的速度快,那么其中一些线程将被main杀死
所以最好在主要比赛结束前等待他们结束。