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

发布于 2024-10-14 09:51:29 字数 840 浏览 3 评论 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之前,它可以在释放期间发生变化。老实说,我也担心由于性能和死锁而锁定整个函数。

Ok first I must preface this question with a disclaimer, I'm really new to threading so this may be a 'newbie' question but I searched google and couldn't find an answer. As I understand it a critical section is code that can be accessed by two or more threads, the danger being one thread will overwrite a value before the other is finished and vice versa. What can you do about changes made outside of your class for example, I have a line monitoring program:

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

and on another thread I have something like this:

if(condition)
    provider.SetNumber(numberToSet);

Now I'm afraid that in the first function I get currentNumber which is 5, right after that on another thread the number is set to 7 and then it rewrites the 7 to 6, ignoring the change made by the thread that set it to 7.

Is there anyway to lock provider.SetNumber until the first function finishes? The critical section is basically the currentNumber which can be changed by many places in the program.

I hope I made myself clear, if not let me know and I will try to explain myself better.

EDIT:
Also I made the functions really short for the example. In reality the function is much longer and makes changes to currentNumber many times so I don't really want to put a lock around the entire function. If I lock every call to provider.SetNumber and release it after I finish it can change during the time it is released before I lock it again to call provider.SetNumber. Honestly I'm also worried about locking the entire function because of performance and deadlock.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

为你拒绝所有暧昧 2024-10-21 09:51:29

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

有几种您感兴趣的方法,ExchangeRead,两者都是线程安全的。

Rather than using the lock() keywords I'd suggested seeing if you can use the Interlocked class which is designed for small operations. It's got much less overhead than lock, in fact can be down to a single CPU instruction on some CPUs.

There are a couple of methods of interest for you, Exchange and Read, both of which are thread safe.

乖不如嘢 2024-10-21 09:51:29

您想要查看Lock< /code>关键字。另外,您可能希望学习本教程C# 中的线程

You want to look into the Lock keyword. Also you might want to this tutorial to Threading in C#.

吻安 2024-10-21 09:51:29

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

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

以及

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

如果条件依赖于 numberToSet,您应该在整个块周围使用锁定语句。另请注意,someObject 必须是同一个对象。

As Filip said, lock is useful here.
Not only should you lock on provider.SetNumber(currentNumber), you also need to lock on any conditional that the setter depends on.

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

as well as

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

If condition is reliant on numberToSet, you should take the lock statement around the whole block. Also note that someObject must be the same object.

柠檬 2024-10-21 09:51:29

您可以使用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);
  }
}

You can use the lock statement, to enter a critical section with mutual exclusion. The lock will use the object's reference to differentiate one critical section from another, you must have the same reference for all your lock if it accesses to the same elements.

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

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

That will change your code to :

int currentNumber = provider.GetCurrentNumber();

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

And :

if(condition)
{
  lock (locker)
  {
    provider.SetNumber(numberToSet);
  }
}
七禾 2024-10-21 09:51:29

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

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

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

In your SetNumber method you can simply use a lock statement:

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

Also, note that in your example currentNumber is a primitive (int), which means that variable's value won't be overwritten should your provider's actual data member's value change.

疯了 2024-10-21 09:51:29

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

创建关键部分很容易

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

注意:这应该被替换为一些内部对象......

Well first of im not so good with threading but a critical section is a part of your code that can only be accessed my one thread at a time not the other way around..

To create a critical section is easy

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

note: that this should be replaced with some internal object...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文