【问题标题】:How to handle signal once in many threads in C#如何在 C# 的多个线程中处理一次信号
【发布时间】:2011-04-28 00:47:18
【问题描述】:

在 C# 中,我有多个对象,每个对象都有自己的线程,可以根据外部信号执行操作。所有对象都保留所有其他对象的列表。
我需要到达的信号仅在单线程中的单个对象中执行。此信号将删除所有对象,因此多个信号不会到达同一个对象。
最有可能信号会同时到达他们所有的地方,但也有可能是迟到的。由于信号将导致它们全部销毁并且不会传递给已销毁的信号,因此可以忽略延迟。
我虽然想做lock(this),然后锁定列表中的每个对象,但我不知道如何在不为其创建范围的情况下执行锁定(意味着手动解锁,而不是在锁定范围结束时)。
另一个问题是,如果一个已经开始锁定而另一个试图锁定它,它只会等待而不是忽略它。
此外,我无法控制Thread 对象,即使有办法检索它们,对Thread 对象的任何触摸都可能会使应用程序崩溃。诸如暂停所有其他线程之类的答案将不起作用。
那么如何让信号只被一个对象作用而被其余对象忽略呢?

【问题讨论】:

  • 几件事:至少,请提供一些伪代码,说明您的对象如何获取消息以及它们如何破坏其他对象和/或它们自己。你的对象在做什么?如果所有对象都被销毁,谁会收到迟到的信号?
  • 另外,收到消息的对象如何知道所有其他需要删除的对象?
  • 我不知道它是如何工作的……它是一个使用嵌入式.NET 框架的C++ 框架。它在收到信号时调用我的对象中的一个方法,当我希望它被销毁时我应该调用destroy方法。我确实保留了我所有对象中所有对象的列表。当一个对象被销毁时,它的所有引用都会以某种方式设置为 null。
  • 你能提供它如何操作的通用界面吗? IE。对象如何在您的系统中接收消息?

标签: c# multithreading


【解决方案1】:

您可以有一个父线程来跟踪已处理的内容。当线程接收到新信号时,您可以询问父级该信号是否已被处理。如果不是,则处理它,然后父级将其他人锁定。

你也可以考虑使用消息队列,每个信号只会被一个线程接收。

【讨论】:

  • 父线程是个好主意。我只会在构造其中一个线程时将其标记为父线程,并将其传递给所有其他加入它的线程。
【解决方案2】:

我想我明白现在发生了什么,但如果这是错误的,请纠正我:

  • 大概你所有的对象都属于同一类型
  • 对象列表是静态的(如果不是,则考虑这样做更有效)
  • 任何对象都可以接收信号,但只有一个对象会处理它。

所以如果我们假设你每个对象都有一个接收信号的方法,那么我认为这可能是一个不错的设计:

public class Thing
{
    private static volatile bool _tooLate = false;
    private static List<Thing> _theWorld; // contains everything
    private static readonly object _sync = new object();

    public Thing(){/*...*/}

    // a static method to process the signal
    public static void ProcessSignal(Signal signal)
    {
        // make sure you're not late to the party
        if(signal == signal.DestroyTheWorld && !_tooLate)
        {
            // You won't destroy the world yet... but you'll give it a shot!
            BringAboutTheDestruction();
        }
    }

    // a static method to bring about the destruction of the world! MUAHAHAHAHA
    public static void BringAboutTheDestruction()
    {
        // you might not be late for the party, 
        // but you still have to get past the doorman
        lock(_sync)
        {
            // you finally got in, but you might get kicked out!
            if(!_tooLate)
            {
                // Apocalypse now!!! There is no turning back
                foreach(Thing t in _theWorld)
                {
                    t.Destroy();
                }
                _theWorld.Clear();
            }
            _tooLate = true;
        }
    }
}

【讨论】:

    【解决方案3】:

    您始终可以使用 EventWaitHandle 类。每个线程有两个,一个用于线程需要做某事的时候,一个用于关闭所有线程。第一个是线程本地的,第二个是全局的:

    void CreateThreads ()
    {
       global_event = new EventWaitHandle (false, EventResetMode.AutoReset);
    
       for each thread to create
       {
         create thread a pass the global_event object
       }
    }
    
    void ThreadProc (EventWaitHandle global_event)
    {
      create local_event; // this is set when the thread needs to do something
    
      bool quit = false;
    
      while (!quit)
      {
        switch (EventWaitHandle.WaitAny (new WaitHandle [] { global_event, local_event })
        {
        case 0: // global 
          shut down other threads
          quit = true;
          break;
    
        case 1: // local
          do local signal processing
          break;
        }
      }
    }
    

    EventResetMode.AutoReset 标志意味着只有一个等待事件的线程将被释放。当然,你无法预测是哪一个。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-04
      • 1970-01-01
      • 2012-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-21
      相关资源
      最近更新 更多