-4

ManualResetEvent を作成し、それをインスタンスの SortedList に格納し、シグナリングを待機してから、いくつかの作業を行ってイベントを破棄する "Add2List" メソッドがあります。
リモートサーバーをリッスンし、Guidに従って保存された手動イベントを通知する別のメソッド「DoSomething」があります。

マルチスレッド コンテキストでは、マルチ スレッドはメソッド「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 が <2, MyManualEvent> を破棄したか、 th2 が <1, MyManualEvent> を破棄したためです。このプログラムを 3 回実行すると、iteration12、iteration45、および iteration0 (最初) で例外が発生します。

4

1 に答える 1