4

如果我有一个可以/将在任何给定时间点由多个线程访问的数组,究竟是什么导致它是非线程安全的,以及为确保该数组在大多数情况下是线程安全的而采取的步骤情况?

我在互联网上进行了广泛的查看,几乎没有发现关于这个主题的信息,一切似乎都是特定的场景(例如,这个数组,这两个线程正在像这样访问线程安全,等等)。我真的很希望有人可以回答我在顶部列出的问题,或者是否有人可以指出解释上述项目的好文件。

编辑:在 MSDN 上环顾四周后,我找到了 ArrayList 类。当您使用 synchronize 方法时,它会为给定列表返回一个线程安全的包装器。在列表中设置数据时(即 list1[someNumber] = anotherNumber;),包装器会自动处理锁定列表,还是仍然需要锁定它?

4

4 回答 4

6

当两个线程访问完全相同的资源(例如,不是本地副本,而是实际上是同一资源的相同副本)时,可能会发生很多事情。在最明显的情况下,如果 Thread #1 正在访问资源并且 Thread #2 在读取过程中对其进行了更改,则可能会发生一些不可预知的行为。即使使用像整数这样简单的东西,也可能会出现逻辑错误,因此请尝试想象不正确地使用更复杂的东西可能导致的恐怖,例如声明为静态的数据库访问类。

处理这个问题的经典方法是锁定敏感资源,这样一次只有一个线程可以使用它。所以在上面的例子中,线程#1 会请求一个资源的锁并被授予它,然后进入读取它需要读取的内容。线程#2 会在读取过程中出现并请求锁定资源,但由于线程#1 正在使用它而被拒绝并被告知等待。当线程 #1 完成时,它会释放锁,线程 #2 可以继续进行。

还有其他情况,但这说明了最基本的问题和解决方案之一。在 C# 中,您可以:

1) 使用由框架管理为可锁定的特定 .NET 对象(如 Scorpion-Prince到 SynchronizedCollection 的链接

2) 使用[MethodImpl(MethodImplOptions.Synchronized)]指示执行危险操作的特定方法一次只能由一个线程使用

3) 使用lock 语句隔离正在执行潜在危险的特定代码行

哪种方法最好取决于您的情况。

于 2012-06-08T16:23:02.877 回答
4

如果我有一个可以/将在任何给定时间点由多个线程访问的数组,究竟是什么导致它是非线程安全的,以及为确保该数组在大多数情况下是线程安全的而采取的步骤情况?

一般而言,数组不是线程安全的事实是,如果您不同步访问数组,则两个或多个线程可能正在修改数组的内容。

一般来说,例如,假设您有线程 1 执行此工作:

for (int i = 0; i < array.Length; i++)
{
   array[i] = "Hello";
}

线程 2 做这项工作(在同一个共享数组上)

for (int i = 0; i < array.Length; i++)
{
   array[i] = "Goodbye";
}

没有任何东西可以同步线程,因此您的结果将取决于哪个线程首先赢得比赛。它可以是“Hello”或“Goodbye”,以某种随机顺序排列,但始终至少是“Hello”或“Goodbye”。

CLR 保证字符串“Hello”或“Goodbye”的实际写入是原子的。也就是说,值'Hello'的写入不能被试图写入'Goodbye'的线程中断。一个必须发生在另一个之前或之后,绝不能介于两者之间。

所以你需要创建某种同步机制来防止数组相互踩踏。您可以通过使用lockC# 中的语句来完成此操作。

于 2012-06-08T16:14:04.033 回答
2

C# 3.0 及更高版本提供了一个名为SynchronizedCollection的泛型集合类,它“提供了一个线程安全的集合,其中包含由泛型参数指定的类型的对象作为元素。”

于 2012-06-08T15:55:39.893 回答
0

数组是线程安全的,如果它被命名public并且static关键字 - 不保证即时 - 因为它System.Array实现了ICollection定义一些同步方法以支持同步机制的接口。

但是,通过数组项进行枚举的编码是不安全的,开发人员应执行lock语句以确保在数组枚举期间不会更改数组。

前任:

Array arrThreadSafe = new string[] {"We", "are", "safe"};
lock(arrThreadSafe.SyncRoot)
{
   foreach (string item in arrThreadSafe)
   {
     Console.WriteLine(item);
   }
}
于 2014-11-01T08:50:24.190 回答