编组站跨线程活动(Marshalling Events Across Threads)

2019-07-30 04:10发布

我想这可能被标记为重复的和封闭的,但我不能为我的生活找到一个清晰,简洁的回答这个问题。 所有的答复和处理资源几乎完全与Windows窗体和利用预先构建的工具类,如BackgroundWorker的。 我非常想了解其核心这个概念,所以我可以申请的基础知识到其他线程的实现。

我想达到什么样的一个简单的例子:

//timer running on a seperate thread and raising events at set intervals
//incomplete, but functional, except for the cross-thread event raising
class Timer
{
    //how often the Alarm event is raised
    float _alarmInterval;
    //stopwatch to keep time
    Stopwatch _stopwatch;
    //this Thread used to repeatedly check for events to raise
    Thread _timerThread;
    //used to pause the timer
    bool _paused;
    //used to determine Alarm event raises
    float _timeOfLastAlarm = 0;

    //this is the event I want to raise on the Main Thread
    public event EventHandler Alarm;

    //Constructor
    public Timer(float alarmInterval)
    {
        _alarmInterval = alarmInterval;
        _stopwatch = new Stopwatch();
        _timerThread = new Thread(new ThreadStart(Initiate));
    }

    //toggles the Timer
    //do I need to marshall this data back and forth as well? or is the
    //_paused boolean in a shared data pool that both threads can access?
    public void Pause()
    {
        _paused = (!_paused);            
    }

    //little Helper to start the Stopwatch and loop over the Main method
    void Initiate()
    {
        _stopwatch.Start();
        while (true) Main();    
    }

    //checks for Alarm events
    void Main()
    {
        if (_paused && _stopwatch.IsRunning) _stopwatch.Stop();
        if (!_paused && !_stopwatch.IsRunning) _stopwatch.Start();
        if (_stopwatch.Elapsed.TotalSeconds > _timeOfLastAlarm)
        {
            _timeOfLastAlarm = _stopwatch.Elapsed.Seconds;
            RaiseAlarm();
        }
    }
}

这里有两个问题; 主要是,我如何得到事件的主线程提醒报警事件的当事人。

其次,关于暂停()方法,这将是由主线程上运行的对象被调用; 我可以直接操作),这是通过调用_stopwatch.start(在后台线程创建的秒表/ _ stopwatch.stop()。 如果不是,可以在主螺纹调整_paused布尔以上如示出的是后台线程然后可看到的_paused的新值,并使用它?

我发誓,我做我的研究,但这些(基本和关键的)细节还没有使自己清楚,我还没有。

免责声明:我知道有可用的类,将提供我在Timer类现在描述的是确切的特定功能。 (事实上​​,我相信该类称为只是,Threading.Timer)不过,我的问题是不是一个试图帮助我实现Timer类本身,而了解如何执行驱动它的概念。

Answer 1:

注:我在这里写这个,因为那里有意见上没有足够的空间,这当然是不完整的,也不能半一个完整的答案:

我一直使用活动信号无关的代码做一些事情,所以这是我怎么描述我的意图。 原谅我,虽然,我不知道我看到与编组另一种类型的数据(信号),编组和事件之间的差别。

从概念上讲都可以被视为事件。 使用提供的同步/ signalining对象,并试图通过urself实现这样的事情,之间的区别是谁,以及如何能够完成任务。

在.NET中的事件只是一个代表,指针的方法列表时,事件的触发提供它应该执行。 什么youre谈论(编组的情况下),如果我理解正确的话,是分享有事的事件对象,而signalig通常哪些共享下手的对象会谈,双方线程的概念“知道”事情发生通过检查其状态或者manualy或automatily(由.NET和窗户依靠提供的工具)。

在最基本的情况下,您可以通过使用一个实现这样的信令概念boolean变量,一个线程不断循环来检查的价值boolean是真实的,而另一个设置这样,作为一种信号东西happend。 由.NET提供的不同信号的工具做到这一点在较低的资源浪费满耳,也通过不执行等待线程,只要世界上没有信号(布尔等于假),但在概念上,这是同样的想法。



Answer 2:

现有的线程上你不能神奇地执行代码。
相反,你需要将现有的线程来显式执行你的代码,使用线程安全的数据结构来告诉它做什么。

这是怎么Control.Invoke工作(这又是如何BackgroundWorker作品)。
WiinForms运行在一个消息循环Application.Run()看起来大致是这样的:

while(true) {
    var message = GetMessage();  //Windows API call
    ProcessMessage(message);
}

Control.Invoke()发送Windows消息(使用线程安全的消息传递Windows中的代码),告诉它来运行你的委托。 ProcessMessage (其执行在UI线程上)将捕获该消息并执行委托。

如果你想这个做你自己,你需要编写自己的循环。 您可以使用在.NET 4.0中新的线程安全的生产者-消费者收藏此,也可以使用委托字段( Interlocked.CompareExchange )和AutoResetEvent自己去做。



文章来源: Marshalling Events Across Threads