简单的线程问题,锁定非本地更改

时间:2011-01-27 09:48:56

标签: c# .net multithreading locking critical-section

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

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。老实说,我也担心由于性能和死锁而锁定整个函数。

6 个答案:

答案 0 :(得分:2)

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

您可以使用以下几种方法,ExchangeRead,这两种方法都是线程安全的。

答案 1 :(得分:0)

您想查看Lock关键字。您也可以将本教程发送到Threading in C#

答案 2 :(得分:0)

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

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

以及

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

如果condition依赖于numberToSet,则应该在整个块周围使用lock语句。另请注意,someObject必须是相同的对象。

答案 3 :(得分: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);
  }
}

答案 4 :(得分:0)

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

创建关键部分很容易

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

注意:应替换为某个内部对象......

答案 5 :(得分:0)

在您的SetNumber方法中,您只需使用锁定语句:

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

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