【问题标题】:Disposing a manualResetevent on another thread在另一个线程上处理 manualResetevent
【发布时间】:2017-10-04 19:35:55
【问题描述】:

类似于this question 我有一个带有私有 ManualReset 事件的类:

class A {
       private ManualResetEvent mre = new ManualResetEvent(true);
       private void Method(){
            //do something
            mre.Reset();
       }      
       public bool WaitForItem(int timeout){
           try{
               return mre.WaitOne(timeout)
           }catch(ObjectDisposedException){
               return false;
           }
      }
      public void Dispose(){
           mre.Dispose();
      }
}

我如何检查 Dispose 何时被调用 WaitForItem 方法返回 false,并且不会阻塞等待。

代码类似于:

   A a = new A(1);
   a.Method();
   bool finished = true;
   Thread t1 = new Thread(() =>
   {
       finished = a.WaitForItem(Timeout.Infinite);
   });
   Thread t2 = new Thread(() =>
   {
       a.Dispose();
   });
   t1.Start();
   t2.Start();
   t1.Join();
   t2.Join();

永远等待一个项目的代码块(t1.Join())。我知道调用Close,这也是处理对象的一种方式,不会影响句柄的状态,但是我怎样才能以false退出方法(捕获ObjectDisposedException)?

即使不是在第二个线程上调用 a.Dispose() 而是调用另一个处理 ManualResetEvent 的方法,而是调用 WaitOne() 它被阻塞了。

【问题讨论】:

  • 您遇到此问题表明您的应用程序设计存在问题。但如果你真的需要这样做,试试ManualResetEventSlim 并使用Wait(CancellationToken) 方法。只需在处理 MRE 之前更改您的 Dispose 方法以设置取消令牌。不过,老实说,您需要重新考虑您的设计。这样的事情真的不应该是必要的。

标签: c# multithreading


【解决方案1】:

ObjectDisposedException 仅在调用成员函数之前已释放对象时引发。这在您的情况下不会发生,因为函数 mre.WaitOne(timeout)mre.Dispose() 之前被调用。

曾经简单的解决方法是在具有较短超时值的循环中调用mre.WaitOne(timeout) 函数。例如一个人想要10 seconds 超时 WaitForItem 函数然后 mre.WaitOne(timeout) 可以在 1 秒超时后被调用,它会在 10 次尝试后放弃。

WaitForItem 函数的典型实现如下所述。 WaitForItem 有 3 个可能的返回值。

1 = 在mre 上触发设置 0 = 在指定的超时时间内未触发设置 -1 = 对象在超时前处置。

public int WaitForItem(int timeout){
   try{
       int nReturnCode = 0;
       int nTimeElapsed = 0;
       while (true)
       {
           if (mre.WaitOne(1000))  //just wait for  1 second
           {
               nReturnCode = 1; //Set call on ManualResetEvent
               break;
           }
           else  //Timeout need to repeat
           {
               nTimeElapsed += 1000;
               if (nTimeElapsed > timeout)
               {
                   nReturnCode = 0; //timeout
                   break;
               }
           }
       }
       return nReturnCode;
   }catch(ObjectDisposedException){
       return -1; //Exception 
   }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    • 2017-10-27
    相关资源
    最近更新 更多