具有相同名称的c#2事件,在运行时出现混乱,我应该如何避免这种情况



我有一个方法"Add2List",它创建一个ManualResetEvent并将其存储在实例的SortedList中,然后等待信号,然后做一些工作并处理该事件
我有另一种方法"DoSomething",它监听远程服务器,然后根据Guid向存储的手动事件发送信号。

在多线程上下文中,多线程调用方法"Add2List",因此在sortedlist中可能同时有多个名称相同的手动事件。但这可能会造成混乱。我应该如何避免这种情况?

更简单地说,我写了这个测试代码:

Class Program
{
  static void Main(string[] args)
  {
    StringBuilder str = new StringBuilder();//a string to record what happened
    //test iteratively
    for(int i=0;i<100;i++)
    {
      EventHolder holder = new EventHolder();
      Signaler ob2 = new Signaler();
      Thread th1 = new Thread(holder.Add2List);
      Thread th2 = new Thread(holder.Add2List);
      Thread th3 = new Thread(ob2.DoSomething);
      th1.Start(1);
      th2.Start(2);
      th3.Start();
      //Make sure all thread is ended before the next iteration.
      while(th1.IsAlive){ Thread.Sleep(200); }
      while(th2.IsAlive){ Thread.Sleep(200); }
      while(th3.IsAlive){ Thread.Sleep(200); }
    }
    Console.Read();
  }
  public class EventHolder
  {
    static SortedList<int, ManualResetEvent> MyManualEventList = new SortedList<int, ManualResetEvent>();
    public EventHolder()
    {
      MyManualEventList = new SortedList<int, ManualResetEvent>();
      Signaler.SignalMyManualEvent += OnSignalMyManualEvent;
    }
    void OnSignalMyManualEvent(int listindex)
    {
      try { MyManualEventList[listindex].Set(); }
      catch(Exception e)
      {
        Console.WriteLine("Exception throws at " + System.DateTime.Now.ToString() +" Exception Message:"
        Console.WriteLine(e.Message);
        int temp = 0; //*Here is a breakpoint! To watch local variables when exception happens.
      }
    }
    public void Add2List(object listindex)
    {
      ManualResetEvent MyManualEvent = new ManualResetEvent(false);
      MyManualEvent.Reset();
      MyManualEventList.Add((int)listindex, eve);
      //in this test, this countdownevent need to be signaled twice, for it has to wait until all 2 event been added to MyManualEventList
      Signaler.StartTrySignal.Signal();
      MyManualEvent.WaitOne();
      Console.WriteLine("Event" + ((int)listindex).ToString() + " been detected at " + System.DateTime.Now.Tostring());
      MyManualEvent.Dispose();
    }
  }
  public class Signaler
  {
    public delegate void Signalhandler(int listindex);
    public static event Signalhandler SignalMyManualEvent;
    public static CountDownEvent StartTrySignal = new CountDownEvent(2); // signaled twice so that the 2 manual events were added to sortedlist
    void RaiseSignalMyManualEvent(int listindex)
    {
      var vr = SignalMyManualEvent;
      if(vr != null)
        vr(listindex);
    }
    int i = 0, j = 0, k = 0;
    // here i use 2 prime numbers to simulate the happening of 2 random events
    public Signaler()
    {
      StartTrySignal.Reset();
    }
    public void DoSomething()
    {
      StartTrySignal.Wait(); // wait for the 2 manual events been added to sortedlist
      //To signal MyManualEventList[1] or MyManualEventList[2]
      while(i + j == 0)
      {
        Random rnd = new Random();
        k = rnd.Next();
        if(k % 613 == 0) { i = 1; Console.WriteLine("Event1 Raised!"; RaiseSignalMyManualEvent(1); }
        else if(k % 617 == 0) { j = 1;  Console.WriteLine("Event1 Raised!"; RaiseSignalMyManualEvent(2); }
      }
      //if MyManualEventList[1] has not been signaled, wait something to happen, and signal it.
      while(i == 0)
      {
        Random rnd = new Random();
        k = rnd.Next();
        if(k % 613 == 0)
        {
          i = 1;
          if(j>0)
          {
            m++;
            Console.WriteLine("All 2 Events Raised!  - iteration " + m.ToString());
          }
          RaiseSignalMyManualEvent(1);
        }
      }
      //if MyManualEventList[2] has not been signaled, wait something to happen, and signal it.
      while(j == 0)
      {
        Random rnd = new Random();
        k = rnd.Next();
        if(k % 617 == 0)
        {
          j = 1;
          m++;
          Console.WriteLine("All 2 Events Raised!  - iteration " + m.ToString());
          RaiseSignalMyManualEvent(2); 
        }
      }
    }
  }
  public class Counter //Provide a number to record iteration
  {
    public static int m = 0;
  }
}

结果:很抱歉没有足够的信誉来发布图片
在有断点的行,系统抛出异常"给定的键不在字典中"。这种异常随机发生,有时是因为th1 displayd<2、MyManualEvent>或th2disposed<1,MyManualEvent>,有时没有一个被处理,但就是找不到任何人。我运行这个程序3次,异常发生在迭代12、迭代45和迭代0(在开始时)。

OK 2回答

1:您的代码在"All events"之后返回"Event 1",因为两个console.write行处于竞争状态(最后一个while循环从未迭代)

2:"系统"在两个ManualResetEvent对象之间有区别,因为它引用了您将它们放入的SortedList。即

static SortedList<int, ManualResetEvent> MyManualEventList 
       = new SortedList<int, ManualResetEvent>();
  public EventHolder() { Signaler.SignalMyManualEvent 
       += OnSignalMyManualEvent; }
  void OnSignalMyManualEvent(int listindex)
  {

MyManualEventList[listindex].Set();

  }

当引发事件1时,调用SortedList中项目1上的set;当引发事件2时,调用列表中项目2上的set。

这很糟糕,因为调用代码不知道它允许哪个线程继续,并且很可能会得到一个空异常

相关内容

  • 没有找到相关文章

最新更新