问题
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 lock
s and Queue
s 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