0

好的,首先我必须在这个问题前加上免责声明,我对线程很陌生,所以这可能是一个“新手”问题,但我搜索了谷歌并找不到答案。据我了解,关键部分是可以由两个或多个线程访问的代码,一个线程的危险将在另一个线程完成之前覆盖一个值,反之亦然。您可以对课外所做的更改做些什么,例如,我有一个线路监控程序:

int currentNumber = provider.GetCurrentNumber();
if(provider.CanPassNumber(false, currentNumber))
{
currentNumber++;
provider.SetNumber(currentNumber);
}

在另一个线程上,我有这样的事情:

if(condition)
    provider.SetNumber(numberToSet);

现在我担心在第一个函数中我得到 currentNumber 5,紧接着在另一个线程上将数字设置为 7,然后将 7 重写为 6,忽略将其设置为 7 的线程所做的更改.

无论如何要锁定 provider.SetNumber 直到第一个函数完成?临界区基本上是 currentNumber,可以在程序中的许多地方更改。

我希望我说清楚了,如果不让我知道,我会尝试更好地解释自己。

编辑:我也让这个例子的功能真的很短。实际上,该函数要长得多,并且对 currentNumber 进行了多次更改,因此我真的不想锁定整个函数。如果我锁定对 provider.SetNumber 的每个调用并在完成后释放它,它可以在它被释放的时间内更改,然后我再次锁定它以调用 provider.SetNumber。老实说,我也担心由于性能和死锁而锁定整个功能。

4

6 回答 6

2

我建议不要使用lock()关键字,而是看看您是否可以使用专为小型操作设计的Interlocked类。它的开销比锁要少得多,实际上可以降低到某些 CPU 上的单个 CPU 指令。

有几个你感兴趣的方法,ExchangeRead,它们都是线程安全的。

于 2011-01-27T10:00:41.927 回答
0

正如菲利普所说,锁在这里很有用。您不仅应该锁定 provider.SetNumber(currentNumber),还需要锁定 setter 所依赖的任何条件。

lock(someObject)
{
  if(provider.CanPassNumber(false, currentNumber))
  {
    currentNumber++;
    provider.SetNumber(currentNumber);
  }
}

if(condition)
{
  lock(someObject)
  {
    provider.SetNumber(numberToSet);
  }
}

如果条件依赖于 numberToSet,则应该在整个块周围使用 lock 语句。还要注意 someObject 必须是同一个对象。

于 2011-01-27T09:56:19.957 回答
0

您可以使用该lock语句,进入一个互斥的临界区。将使用对象的引用来区分一个关键部分和另一个,如果它访问相同的元素lock,您必须对所有您的引用具有相同的引用。lock

// Define an object which can be locked in your class.
object locker = new object();

// Add around your critical sections the following :
lock (locker) { /* ... */ }

这会将您的代码更改为:

int currentNumber = provider.GetCurrentNumber();

lock (locker)
{
  if(provider.CanPassNumber(false, currentNumber))
  {
    currentNumber++;
    provider.SetNumber(currentNumber);
  }
}

和 :

if(condition)
{
  lock (locker)
  {
    provider.SetNumber(numberToSet);
  }
}
于 2011-01-27T09:57:51.923 回答
0

好吧,首先我不太擅长线程,但关键部分是代码的一部分,一次只能访问我的一个线程,而不是相反。

创建临界区很容易

Lock(this)
{
    //Only one thread can run this at a time
}

注意:应该用一些内部对象替换......

于 2011-01-27T09:57:57.470 回答
0

在您的 SetNumber 方法中,您可以简单地使用 lock 语句:

public class MyProvider {
     object numberLock = new object();
     ...
     public void SetNumber(int num) {
          lock(numberLock) {
               // Do Stuff
          }
     }
}

另外,请注意,在您的示例currentNumber中是一个原语(int),这意味着如果您的提供者的实际数据成员的值发生变化,变量的值不会被覆盖。

于 2011-01-27T09:57:58.403 回答
0

您想查看Lock关键字。此外,您可能希望本教程了解C# 中的线程

于 2011-01-27T09:53:11.967 回答