I have extensively tried to search for this matter and could not reach any conclusion. I am using Xamarin with Visual Studio to design an app for Android in C# language. The app runs an async task which reads samples from the device microphone. So far there is no control of timing for this task. The code is as follows:
button.Click += async delegate
{
//do some other stuff
await read_mic_task();
}
The read_mic_task() is an async Task in which I read the samples from the microphone. I am measuring time between one and other execution using a Stopwatch and I can see the task runs with random periods. I would like to perform this task periodically and, despite searching a lot, I got nothing. Could you please give a help?
Thanks in advance!
There are multiple possibilities if you also want to share it across platforms i would go with system threading timer. This timer can also be used in a portable class.
You can use it for example like:
private System.Threading.Timer _timer;
...
// setup timer with callback
_timer = new System.Threading.Timer(OnTimerTick);
// start timer: duetime = 0 when to first execute callback (0 = right now) and intervall 5s
_timer.Change(0, 5000);
...
// stop timer
_timer.Change(Timeout.Infinite, Timeout.Infinite);
...
private void OnTimerTick(object state)
{
// do the intervall stuff here
}
Related
In my application I have a small number of threads (5) performing the following method non stop:
private void ThreadMethod()
{
while(true)
{
if(CurrentItem != null)
{
HandleCurrentItem();
}
Thread.Sleep(200);
}
}
From what I've seen around this is not a recommended practice, but most of the arguments is because you don't have responsiveness and you cannot cancel the thread or the timing isn't precise. None of those are an issue for me, however I'm concerned about wasting too much CPU resources in this. From what I've seen here at 01:05:35 the processor gets full utilization when you call the Sleep method.
My questions:
Is this a decent solution in my scenario?
If not, how to do it better?
Note: I'm using .Net Framework 4.0
Note 2: those threads are located in different instances of a class, so the CurrentItem is a different object for each thread.
You could make the method async and make it await:
private async void ThreadMethod()
{
while(true)
{
if(CurrentItem != null)
{
HandleCurrentItem();
}
await Task.Delay(200);
}
}
This won't block the thread
Note Async await keywords will only work with .Net 4.0 on visual studio 2012+ by using Microsoft.Bcl.Async (you can get this package on nuget).
You can also use this snippet (credits to: Calvin Fisher):
new System.Threading.ManualResetEvent(false).WaitOne(1000);
You could also use an Timer instead of sleeping when you want to execute something 200 miliseconds after the last action. This won't spin lock the processor.
var timer = new Timer(200);
timer.Elapsed += (sender, args) =>
{
if(CurrentItem != null)
HandleCurrentItem();
};
timer.AutoReset = true;
timer.Start();
The .NET Framework Class Library includes four classes named Timer, each of which offers different functionality:
System.Timers.Timer, which fires an event and executes the code in one or more event sinks at regular intervals. The class is intended for use as a server-based or service component in a multithreaded environment; it has no user interface and is not visible at runtime.
System.Threading.Timer, which executes a single callback method on a thread pool thread at regular intervals. The callback method is defined when the timer is instantiated and cannot be changed. Like the System.Timers.Timer class, this class is intended for use as a server-based or service component in a multithreaded environment; it has no user interface and is not visible at runtime.
System.Windows.Forms.Timer, a Windows Forms component that fires an event and executes the code in one or more event sinks at regular intervals. The component has no user interface and is designed for use in a single-threaded environment; it executes on the UI thread.
System.Web.UI.Timer, an ASP.NET component that performs asynchronous or synchronous web page postbacks at a regular interval.
You can achieve a clean implementation by using Hangfire. This will give you more control over your tasks and you will also be getting a feedback if the function executed or failed.
You can create a scheduled job like this:
RecurringJob.AddOrUpdate(() => Console.WriteLine("Recurring!"),Cron.Daily);
There are many more options which you can explore in the documentation.
You can use AutoRestEvent
private void ThreadMethod()
{
AutoResetEvent _restEvent = new AutoResetEvent(false);
_restEvent.Reset();
while(true)
{
if(CurrentItem != null)
{
HandleCurrentItem();
}
_restEvent.WaitOne(200); // Set a timeout in ms.
}
}
My service will run daily tasks at multiple times. Here is my service code:
private DateTime m_scheduleTime;
private List<Task> m_tasksList; // Task includes id and time ("23:00")
protected override void OnStart(string[] args) {
SetSchedule();
}
private void SetSchedule()
{
Timer[] timers = new Timer[m_tasksList.Count];
int iHours = 0; int iMinutes = 0;
for (int i = 0; i < timers.Length; i++)
{
iHours = Int16.Parse(m_tasksList[i].Time.Split(':')[0]);
iMinutes = Int16.Parse(m_tasksList[i].Time.Split(':')[1]);
m_scheduleTime = DateTime.Today.AddDays(1).AddHours(iHours).AddMinutes(iMinutes);
timers[i] = new Timer();
timers[i].Enabled = true;
timers[i].Interval = m_scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;
timers[i].Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
}
}
protected void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
DoWork(int taskId);
}
The code above is not tested, I built it from relevant code samples. So my problems are I don't know whether I am on the right track and if I'm right, I don't know which timer fires the _Elapsed event so that I can pass respective parameter. Any better solution would be appreciated!
You'd likely have better results using a single System.Threading.Timer that expires periodically at some minimum resolution, say every 60 seconds.
When your service starts, calculate the next scheduled run time for all of your tasks, inserting them into a priority queue as you go. The priority queue should be ordered by the scheduled run time.
Each time your timer expires, evaluate the scheduled run time of the task at the head of your queue. If the task's run time has been reached, pop it from the queue and push it to queue where it will be executed by your worker threads. Repeat this process until you either run out of tasks in the queue or find a task that is not yet ready to run.
Once a task has completed, calculate it's next scheduled run time and insert it into the scheduled priority queue.
If your service is purely for the purpose of running these scheduled tasks, I would suggest that you consider using the Windows Task Scheduler instead. Honestly, even if your service provides other functionality, using the Windows Task Scheduler to run periodic tasks will still be a better option than trying to roll your own scheduler.
You can find a managed wrapper for the Windows Task Scheduler, here http://taskscheduler.codeplex.com/. I have no knowledge of this wrapper, I found it referenced in this question: C# API for Task Scheduler 2.0.
Register a background task:
string myTaskName = "Task";
foreach (var cur in BackgroundTaskRegistration.AllTasks)
if (cur.Value.Name == myTaskName)
{
return;
}
await BackgroundExecutionManager.RequestAccessAsync();
BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder
{
Name = "Task",
TaskEntryPoint = "Background.Task"
};
taskBuilder.SetTrigger(new TimeTrigger(15, true));
BackgroundTaskRegistration myFirstTask = taskBuilder.Register();
Background task is created in the Windows Runtime Component as a separate class:
public sealed class Task : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
//logic, send http get request, connect to db
deferral.Complete();
}
}
When it is time to perform task- it may run random number of times (1 - 15 times) and then spontaneously terminated and no longer starts,to solve this problem need to re-register task. What could be the reason?
VS show this error when i want run task:
On Windows Phone periodic background tasks are executed at an interval of a minimum of 30 minutes.
Windows has a built-in timer that runs background tasks in 15-minute intervals. Note that on Windows Phone, the interval is 30 minutes.
(Source: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh977059.aspx?f=255&MSPPError=-2147217396)
If I were you I'd change the time interval to something more safe (such as 60 minutes) - you can always try smaller intervals later. And take a look at the oneShot flag, which is set to true in your case. Set it to false to make your task run more than once.
Also your exception does not look healthy. You said it even occurs with the background task being empty - you should fix that, just to be safe.
I'd suggest you to manually start and debug your backgorund task a couple of times using the lifecycle feature in Visual Studio. Maybe there are other things that cause your task to die.
But first check the interval.
I am currently working on a c# project where I need to perform a task so many times every so many seconds.
For example, write to the console 5 times every 1 second. How could I go about doing this.
Thanks for any help you can provide.
You can use a Timer and bind and event to the Timer.Elapsed event.
using System.Timers;
Sample code:
Timer timer = new Timer();
timer.Elapsed += (sender, eventArgs) =>
{
for (int i = 0; i < 5; i++)
{
Console.Write(i);
}
};
Is this an console application, or do you run this on another thread?
For short stuff like this, use a timer. There are two main ones to choose from:
System.Threading.Timer
And:
System.Windows.Forms.Timer
The former uses the ThreadPool, the latter uses UI events. They both expose the ability to specify and interval and either a callback method or event to attach to in order to put custom code.
For longer periods of inactivity, look into scheduling either with the Windows scheduler (the OS one) or a scheduling framework such as Quartz.NET.
Do note that the accuracy of the timers vary, but not really within margins that humans can detect :-)
Also note that the callback of the threaded timer will return on an arbitrary ThreadPool thread, so you could effectively end up "multi-threading" the code without realising it.
There is also System.Timers.Timer, it exposes an event. An article about the different timers available can be found here.
I don't think it will affect you, but it's still worth knowing - windows is not a real-time OS; if you ask for something to be done every X milliseconds, it won't be exact, as for how much it will be out depends on a variety of things.
You could create a thread to do it. Especially useful if you want to do a lot of processing! Here's an example of a thread doing work every 1s (1000ms):
public void Start()
{
running = true;
thread = new Thread(new ParameterizedThreadStart(ThreadFunction));
thread.Start();
}
public virtual void ThreadFunction(object o)
{
var insert = false;
while (running)
{
//Do work
Thread.Sleep(1000);
}
}
try this
While (true)
{
for (int i=0; i<5; i++)
{
console ("Hello");
}
//this will pause for 1 sec (1000msec)
Thread.sleep(1000);
}
I'm trying to write a Windows service that runs indefinitely. Windows forms and background programs for Linux don't seem too bad but maybe I'm just horribly inept at Windows Services. Unlike some other sleep or timer related questions I've dug through here, the time to wake up or sleep can be a regular interval, but isn't always such. The program reads from some data files that may instruct it to change its own schedule and this must take effect as of its next wake up time. It seemed quite easy as a console program and behaved perfectly there:
while (true)
{
// Calculate next time to run.
DateTime nextRun = NextWakeup();
TimeSpan nextTime = nextRun - DateTime.Now;
int sleepMs = (int)nextTime.TotalMilliseconds;
// Sleep until scheduled time
System.Threading.Thread.Sleep(sleepMs);
// Do a code cycle of more stuff here...
}
However, when I try to run it as part of a service so that it continues to be active while the user is logged out, the Service Manager stubbornly refuses to start it. I get the lovely 1053 error, "The service did not respond to the start or control request in a timely fashion."
A lot of answers to related questions here seem to suggest going with a timer at all costs over thread sleeping. If I did such a thing instead of the while/sleep combination, how would I go about changing the timer interval at each run? Or is this all perfectly fine and I'm going about setting up my service wrong?
Much thanks in advance!
Windows services must usually respond to a control request (ususally start/stop but also pause/resume) in 30seconds. This means that if you sleep the main thread in the OnStart your service will return the error you refer to.
The way to resolve your issue is to do your work on a separate thread, where you're free to sleep the thread in the way you describe. Just start this thread in the services' OnStart and you should be able to easily return within the 30 second limit.
As an aside, instead of while(true) you should consider the service being stopped must also return in that 30 second limit. If you have a thread sat sleeping the service will not shut down properly without either Aborting the thread (bad) or providing some mechanism for properly exiting the thread. This is exactly why most people go with the polling approach; the service can both determine whether its time to run, or determine whether a stop request has taken place. As long as this poll freqency is <30s the service will always shut down properly.
If you want to use timers its quite easy to do. I'd use System.Timers.Timer and changing its interval is as easy as mytimer.Inverval = nextTime.Seconds or similar.
I'd personally run the timer without AutoReset = false (so it doesn't restart the timer automatically) and then every time it wakes up it runs your "dowork" and then at the end of the dowork you work out when you want it to run next, set the interval as appropriate and then call Start on your timer again.
Of course in your service your start method just sets up the first timer run and then returns so that the startup is nice and quick. On shutdown you just clean up your timer (stop and dispose and such like) and then just return. Nice and clean.
I think you might be looking for something like this:
static class ConsoleProgram
{
static void Main()
{
ServiceBase[] servicesToRun = new ServiceBase[] { new MyService(config, Logger) };
ServiceBase.Run(servicesToRun);
}
}
public partial class MyService : ServiceBase
{
private bool _stopped = true;
protected override void OnStart(string[] args)
{
StartTimer();
}
protected override void OnStop()
{
StopTimer();
}
public void StartTimer()
{
_stopped = false;
Timer t = new Timer(TimerProc);
// Calculate your desired interval here.
t.Change(_config.Interval, new TimeSpan(0, 0, 0, 0, -1));
}
public void StopTimer()
{
_stopped = true;
}
private void TimerProc(object state)
{
// The state object is the Timer object.
Timer t = (Timer) state;
t.Dispose();
ThreadPool.QueueUserWorkItem(DoWork);
if (!_stopped) {
StartTimer();
}
}
}