简体   繁体   English

C#/ C ++ CLI:对Array.Resize使用监视器锁定

[英]c# / c++cli: using monitor lock for Array.Resize

I am using a array m_aoAlternatingJobs in various functions of a class. 我在类的各种函数中使用数组m_aoAlternatingJobs These functions are accessed by different threads. 这些功能由不同的线程访问。 Therefore I am using a Monitor-lock (c++cli) in each function that accesses this array prior to the actual access. 因此,我在实际访问之前访问此数组的每个函数中都使用了Monitor-lock(c ++ cli)。

The problem now is, that in one function I am resizing the array. 现在的问题是,在一个函数中,我正在调整数组的大小。 As described by the MSDN documentation, this will create a new array and copy values, so even if I did not use the Monitor (I am doing on each necessary place), I would not get a program crash in any case, but other threads could access the old array (see also here: stackoverflow: Is Array.Resize(..) threadsafe? ). 如MSDN文档所述,这将创建一个新的数组并复制值,因此,即使我没有使用Monitor(我在每个必要的地方都在做),无论如何我都不会崩溃,但是其他线程可以访问旧数组(另请参见此处: stackoverflow:Array.Resize(..)线程安全吗? )。

If I am using a Monitor directly on the array object, the Monitor fails to exit with SynchronizationLockException because the Exit is called on the new, unlocked object. 如果我直接在数组对象上使用Monitor,则Monitor无法通过SynchronizationLockException退出,因为在新的未锁定对象上调用了Exit。 But I do have to use a lock to avoid resizing the array while in use on another function. 但是我必须使用锁来避免在另一个函数上使用时调整数组的大小。 Thus I'm doing the following trick to avoid access to the array while being resized: 因此,我正在执行以下技巧,以避免在调整大小时访问数组:

void Class1::JobsCount::set (int i_iJobCount)
{
  if (i_iJobCount < 1) i_iJobCount = 1;
  bool bSuccess = false;

  Object^ oRefOld;
  try
  {
    bSuccess = Monitor::TryEnter (m_aoJobs, msc_iMonitorTimeout);
    if (!bSuccess) return;

    oRefOld = m_aoAlternatingJobs;
    Array::Resize (m_aoJobs, i_iJobCount);
  }
  finally
  { if (bSuccess) Monitor::Exit (oRefOld); }
}

I'm not getting an Exception any more, but the more important question is: Will this effectively block access to the array while the resize is being done? 我不再遇到异常,但是更重要的问题是:在调整大小时,这会有效地阻止对数组的访问吗?

Edit: 编辑:
I am aware of the possibility of using a separate lock object, thanks for the advices. 感谢您的建议,我知道可以使用单独的锁定对象。 Nevertheless I would like to receive an answer about the question above. 不过,我想收到有关上述问题的答案。

Correct me if I am wrong but I think you are misunderstanding what Monitor::Lock does. 如果我错了,请纠正我,但我认为您误解了Monitor :: Lock的作用。 Even if you call Monitor::Lock(m_aoJobs), it is not going to prevent a concurrent access from an other piece of code that do not call Monitor::Lock prior to accessing the array. 即使调用Monitor :: Lock(m_aoJobs),也不会阻止在访问数组之前不调用Monitor :: Lock的其他代码并发访问。

The solution is simple: have a dummy object that is only used as an argument to Monitor::Lock. 解决方案很简单:拥有一个虚拟对象,该对象仅用作Monitor :: Lock的参数。 Even if the array is resized, that object will continue to exist and it is not going to cause a crash on Monitor::Exit. 即使调整数组的大小,该对象也将继续存在,并且不会在Monitor :: Exit上导致崩溃。 Then have all pieces of code accessing the array first call Monitor::Lock with the same dummy object and you are good to go. 然后,让所有代码段都访问该数组,首先使用相同的伪对象调用Monitor :: Lock,您就可以开始了。

try {
    Monitor::Lock(m_lock);
    Array::Resize (m_aoJobs, i_iJobCount);
}
finally { Monitor::Exit(m_lock); }

m_lock is the dummy object that should be created in the constructor of the class. m_lock是应该在类的构造函数中创建的虚拟对象。

m_lock = gcnew Object();

The trick you came with might prevent concurrent accesses between the different parts of you code but it is not going to prevent Array::Resize from working with the array at the same time as another part of your code. 附带的技巧可能会阻止代码的不同部分之间的并发访问,但是并不能防止Array :: Resize与代码的另一部分同时使用数组。 It all depends on how Array::Resize is implemented. 这完全取决于Array :: Resize的实现方式。 If the method sets the new value of m_aoJobs just before returning, once the elements of the array have all been copied, then it is going to work. 如果该方法在返回之前设置了m_aoJobs的新值,则一旦数组的所有元素都被复制,它将开始工作。 It's probably what is does. 这可能是做什么的。 However, since it is an implementation detail (unless it is part of the specification of Array::Resize), I would not count on this behavior; 但是,由于它是实现细节(除非它是Array :: Resize规范的一部分),所以我不会指望这种行为。 it might change in the future. 将来可能会改变。

No. This approach not thread-safe. 不可以。这种方法不是线程安全的。 Look at this scenario: 看一下这种情况:

  1. Your function Class1::JobsCount::set in thread 1 locks m_aoJobs 您的函数Class1::JobsCount::set在线程1中锁定m_aoJobs

  2. Function 1 in thread 2 try to locks m_aoJobs, but cannot do it and wait 线程2中的函数1尝试锁定m_aoJobs,但无法执行并等待

  3. Your function Class1::JobsCount::set in thread 1 replace m_aoJobs with new one and unlock old m_aoJobs 您在线程1中的函数Class1::JobsCount::set用新的替换m_aoJobs并解锁旧的m_aoJobs

  4. Function 2 in thread 3 lock new m_aoJobs 线程3中的函数2锁定new m_aoJobs

  5. Function 1 in thread 2 lock old m_aoJobs and modify new one! 线程2中的函数1锁定了旧的m_aoJobs并修改了新的!

This scenario unlikely, but possible. 这种情况不太可能,但是可能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM