C# Passing data to the original thread from Timer

若如初见. 提交于 2020-01-07 02:47:34

问题


This question is possibly a duplicate of How do you add a timer to a C# console application and few other similar questions but couldn't find the answer I'm looking for so asking again.

Question: How do you pass data from the Elapsed event of a Timer (System.Timers.Timer) to the thread that created the timer (that thread may not be the Main thread but another thread spawned by Main)?

I assume there could be some trivial way of achieving this eg. like the BackgroundWorker ProgressChanged event being called in the thread that created the worker, but couldn't find a way in MSDN documentation or SO. Most examples I've seen do some action in the timer thread (https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx) but don't pass anything to the original thread. Needless to say I'm pretty new to C#/.NET so a solution + pointers to references are appreciated.

Edit: I'd prefer not to use the Invoke()/InvokeRequired pattern (cf. How to use safe threading for a timer(Change timer properties from different thread) ) as this is not for a Forms application. I'm tempted to solve this by creating a BackgroundWorker that reports to the original thread at intervals (DoWork will be just a sleep() inside a loop) but thought .NET might have this already and hence the question.


回答1:


Will you consider use a dispatcher? (although you need invoke some method too)

When some thread (maybe not the main thread) create the timer which you mentioned, you can create the dispatcher with the same thread too. After that, dispatcher.invoke() will let the original thread to do those task for you. See the MSDN for more information.




回答2:


It seems to me that a simple locking mechanism is what you need:

private Object _sync = new Object();

void MyTimerFinished() 
{
    lock (_sync)
    {
        // Access shared data
        ...
    }
}

void CodeExecutingInMainThread() 
{
    lock (_sync)
    {
        // Access shared data
        ...
    }   
}



回答3:


Ok, so this is what I came up with (a solution with locks and Queues sounds a bit too complex for me - may be simpler but haven't tried)

public class ReportingTimer
{
    public event EventHandler Elapsed;
    private int _interval;
    private BackgroundWorker _worker;

    public ReportingTimer(int interval)
    {
        _interval = interval;
        _worker = new BackgroundWorker();
        _worker.WorkerReportsProgress = true;
        _worker.WorkerSupportsCancellation = true;

        _worker.DoWork += _worker_DoWork;
        _worker.ProgressChanged += _worker_ProgressChanged;

    }

    public void Start()
    {
        if (!_worker.IsBusy)
        {
            _worker.RunWorkerAsync();
        }
    }

    public void Stop()
    {
        if (_worker.IsBusy)
        {
            _worker.CancelAsync();
        }
    }

    private void _worker_DoWork(object sender, DoWorkEventArgs e)
    {

        while (!_worker.CancellationPending)
        {
            Thread.Sleep(_interval);
            _worker.ReportProgress(1);
        }

        if (_worker.CancellationPending)
        {
            e.Cancel = true;
        }
    }

    private void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        if (!_worker.CancellationPending)
        {
            if (Elapsed != null)
            { 
                Elapsed(this, new EventArgs());
            } 

        }
    }
}

Please critique.

Edit: This serves my purpose and the interface is similar to the Timer class and is actually what I wanted from the stock Timer.



来源:https://stackoverflow.com/questions/31690628/c-sharp-passing-data-to-the-original-thread-from-timer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!