I have a simple C# console application that attaches to an event. I need the program to keep running continuously so it can respond to the event. What is the right way to keep it running?
Here is my application:
using System;
using NAudio.CoreAudioApi;
namespace MaxVolume
{
class Program
{
private const float DesiredLevel = -15;
private static MMDevice _device;
static void Main(string[] args)
{
MMDeviceEnumerator mmde = new MMDeviceEnumerator();
_device = mmde.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
_device.AudioEndpointVolume.MasterVolumeLevel = DesiredLevel;
_device.AudioEndpointVolume.OnVolumeNotification += SetVolume;
}
static void SetVolume(AudioVolumeNotificationData data)
{
if (Math.Abs(data.MasterVolume - DesiredLevel) > 0.1)
{
_device.AudioEndpointVolume.MasterVolumeLevel = DesiredLevel;
}
}
}
}
You can call Console.ReadLine() (if you want to terminate on keystroke), or simply Thread.Sleep(Timeout.Infinite).
In case of async main method, one could also use await Task.Delay(-1);
You can just create a while-loop like so:
while(!eventFired) {}
and then have a field:
private bool eventFired = false;
and then finally when the event is fired make:
eventFired = true;
(if you want it to exit after the event was fired once, that is. if it should run forever see the other answers with sleep and readkey)
NOTE: this is using up a CPU and shouldn't be used in any production, but in a quick-and-dirty test setting it might be worth it.
Related
I'm trying to learn how to use Timers and I'm having troubles with the elapsed event.
What I have is a class where I check some messages from a databatch. But now I want to make a timer where every x period of time check that messages.
I made this code:
public class Program
{
static void Main(string[] args)
{
Message m = new Message();
m.init();
}
}
public class Messages{
private System.Timers.Timer tt;
public void init()
{
tt = new(_conf.Period);
tt.Elapsed += new System.Timers.ElapsedEventHandler(TimerElapsed);
tt.Start();
Console.ReadLine();
}
private void TimerElapsed(object? sender, ElapsedEventArgs e)
{
//Console.WriteLine for test it works
Console.WriteLine(DateTime.UtcNow);
//check my messages
}
}
This doesn't work because it never goes inside TimerElapsed. What am I doing wrong?
Thank you
EDIT: even as a field timer doesn't goes inside elapsed event.
EDIT2: well, I found my problem. I was testing the TimerElapsed with a Console.WriteLine(DateTime.UtcNow) inside of it and it only works if i put after all the code on Init a Console.ReadLine(); Ill edit my code again to show it. I don't understad why I need this readLine so if someone could explain to me would be great.
If you don't like the ReadLine() approach, you can use a polling loop like this instead:
public static void Main (string[] args) {
Messages m = new Messages();
m.init();
ConsoleKeyInfo cki;
do {
while (!Console.KeyAvailable) {
System.Threading.Thread.Sleep(50);
}
cki = Console.ReadKey(true);
} while (cki.Key != ConsoleKey.Escape);
}
This will keep the app alive until the user hits the Escape key.
You should see the timestamps printing at whatever interval you specified.
Usually I avoid using Thread.Sleep except for testing or debugging code.
In the following example, I'm trying to run a console app which will run different classes that will trigger timer ticks at certain times. The idea is to add many more classes that run independent services.
At the moment I'm using, Thread.Sleep(10000); just to keep the console open to allow the code to run.
Surely the Thread.Sleep is blocking some resouces of the CPU?
Is there a better way? (This would be for both Windows and Linux)
while(true)
{
Thread.Sleep(10000);
}
Program:
class Program
{
private static CultureInfo culture = new CultureInfo("en-gb");
static void Main(string[] args)
{
LongRunningClass longRunningClass = new LongRunningClass();
while(true)
{
Thread.Sleep(10000);
}
}
}
Long Running Task:
public class LongRunningClass
{
private Timer timer;
private List<TimeSpan> ScheduleTimes = new List<TimeSpan>()
{
new TimeSpan(4,0,0),
new TimeSpan(6,0,0),
new TimeSpan(21,0,0),
new TimeSpan(23,0,0),
};
public LongRunningClass()
{
this.timer = new Timer(1000);
this.timer.Elapsed += new ElapsedEventHandler(OnTick);
this.timer.Start();
}
protected virtual void OnTick(object sender, ElapsedEventArgs e)
{
this.timer.Stop();
RunLongRunningTask();
double nextTickInterval = 0;
TimeSpan timeOfDayNow = DateTime.Now.TimeOfDay;
foreach (TimeSpan scheduleTime in ScheduleTimes)
{
if (scheduleTime > timeOfDayNow)
{
nextTickInterval = (scheduleTime - timeOfDayNow).TotalMilliseconds;
break;
}
}
// If tick interval not set yet then restart for next day
if (nextTickInterval <= 0)
{
TimeSpan scheduleTime = ScheduleTimes[0].Add(new TimeSpan(1, 0, 0, 0));
nextTickInterval = (scheduleTime - timeOfDayNow).TotalMilliseconds;
}
this.timer.Interval = nextTickInterval;
this.timer.Start();
}
private void RunLongRunningTask()
{
// Long Running Task
}
}
If it's about keeping the console open.
Did you try?
while(true)
{
Console.Read();
}
or just:
Console.Read();
so, it wouldn't close unless you press a key.
You can keep the console open indefinitely until the user cancels by using an AutoResetEvent:
class Program
{
private static AutoResetEvent autoResetEvent;
private static CultureInfo culture = new CultureInfo("en-gb");
static void Main(string[] args)
{
LongRunningClass longRunningClass = new LongRunningClass();
WaitForCancel();
}
/// <summary>
/// When cancel keys Ctrl+C or Ctrl+Break are used, set the event.
/// </summary>
private static void WaitForCancel()
{
autoResetEvent = new AutoResetEvent(false);
Console.WriteLine("Press CTRL + C or CTRL + Break to exit...");
Console.CancelKeyPress += (sender, e) =>
{
e.Cancel = true;
autoResetEvent.Set();
};
autoResetEvent.WaitOne();
}
}
Obviously, this method relies on you knowing when your threads have finished processing.
Surely the Thread.Sleep is blocking some resouces of the CPU?
Its not the CPU you have to worry about, its the memory. You can read the complicated version here, but the simple version is that each thread uses 1MB of memory for the stack. If you are writing an application which needs a lot of threads then you should consider writing async Methods and using Task.Delay. This allows the thread to do something else while the method is waiting, which can reduce the total number of threads needed to process the same workload.
In this case however there isn't much point - while C# 7.1 does support async Main, its just syntactic sugar and doesn't free the thread up to perform other work. In any case I wouldn't loose sleep over using Thread.Sleep in a simple console app like this, or alternatively using something like Console.ReadLine like Neos07 suggests.
Thread.Sleep does still work, but you can consider using Task.Delay as an alternative here, like
await Task.Delay(1000);
I am currently using a thread to run a function every second in a console application C# is a thread the best way to do it? As I have asked a lot of my friends and they have suggested using a timer not a thread for running something every second? If it is a better option to use a timer how would I go about running a function every second using a timer? I have looked around but I am really unsure if that applies to be and if its the right way of going about it in my own way. So can someone tell me the answer and how I can do it?
So what is the best way to run it every second? Before you answer let me just let you know that this is running every second for like 2 days...
My current thread coding
namespace Reality.Game.Misc
{
using Reality;
using Reality.Communication.Outgoing;
using Reality.Game.Rooms;
using Reality.Game.Sessions;
using Reality.Storage;
using System;
using System.Data;
using System.Threading;
public static class JobCacheWorker
{
private static Thread jWorkerThread;
public static void HandleExpiration(Session Session)
{
using (SqlDatabaseClient client = SqlDatabaseManager.GetClient())
{
Session.CharacterInfo.UpdateWorking(client, 0);
}
}
public static void Initialize()
{
jWorkerThread = new Thread(new ThreadStart(JobCacheWorker.ProcessThread));
jWorkerThread.Priority = ThreadPriority.Highest;
jWorkerThread.Name = "JobCacheWorker";
jWorkerThread.Start();
}
public static void CheckEffectExpiry(Session Session)
{
try
{
//RunMyCodeHere...
}
catch (Exception exception)
{
Console.WriteLine("Exception - JobCacheWorker -> " + exception.Message);
}
}
private static void ProcessThread()
{
while (Program.Alive)
{
try
{
foreach (Session Session in SessionManager.Sessions.Values)
{
if (Session != null && Session.Authenticated && !Session.Stopped)
{
CheckEffectExpiry(Session);
Thread.Sleep(1000);
}
}
}
catch (ThreadAbortException exception)
{
Output.WriteLine("ThreadAbortException - JobCacheWorker -> " + exception.Message);
}
catch (ThreadInterruptedException exception2)
{
Output.WriteLine("ThreadInterruptedException - JobCacheWorker -> " + exception2.Message);
}
}
}
}
}
I'd use a System.Threading.Timer because it generally uses less resources than a devoted thread. Here's an example:
using System;
using System.Threading;
namespace Demo
{
public static class Program
{
public static void Main()
{
Console.WriteLine("Starting timer with callback every 1 second.");
Timer timer = new Timer(callback, "Some state", TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
Thread.Sleep(4500); // Wait a bit over 4 seconds.
Console.WriteLine("Changing timer to callback every 2 seconds.");
timer.Change(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));
Thread.Sleep(9000);
timer.Change(-1, -1); // Stop the timer from running.
Console.WriteLine("Done. Press ENTER");
Console.ReadLine();
}
private static void callback(object state)
{
Console.WriteLine("Called back with state = " + state);
}
}
}
This is a good choice for a Console app. However, you must of course bear in mind that the callback is still being done on a separate thread from the main thread, so you must be careful about synchronising resources and variables shared between the callback and the main thread.
you can take a look at System.Threading.Timer which executes a single callback on a thread pool at a regular intervals which make it more accurate than threads.
Here how your code can look like
static void Main(string[] args)
{
TimerCallback tmCallback = CheckEffectExpiry;
Timer timer = new Timer(tmCallback,"test",1000,1000);
Console.WriteLine("Press any key to exit the sample");
Console.ReadLine();
}
static void CheckEffectExpiry(object objectInfo)
{
//TODO put your code
}
If you want the task to run parallel to any current task, then using a thread is not a bad option. Although, since the task is to happen every second, I imagine it is a very small task. In that case, preferably use timer because, lesser code and easier understanding.
To do so, you can refer the System Timer class. It has an example and everything.
But in general, these are the things that you'll be doing:
Create an instance of a timer (Preferably, declare it globally and initialize it in Initialize())
Set the interval (1 second = 1000 millisecond)
Enable the timer
Start it
Optionally, you can even stop it if you want
I have a console application, and I want it to wait till some event is raised. But it executes the code and exits:
static void Main(string[] args)
{
var someObjectInstance = new SomeObject();
someObjectInstance.SomeEvent += SomeEventHandler;
}
static void SomeEventHandler()
{
//Some logic
}
I want to make my application behave like a Windows application where
Application.Run(new Form1());
is called and the message loop is run.
But I don't need neither a message loop nor any form. So it looks like overhead. Is there a more light-weight way to achieve my goal?
First off, unless SomeObject is going to raise the event on a separate thread, this won't work without some form of processing in SomeObject. If it's designed that way, however, this is fairly straightforward.
A very efficient way of handling this is to just wait on a WaitHandle:
private static ManualResetEvent waitHandle = new ManualResetEvent(false);
static void Main(string[] args)
{
var someObjectInstance = new SomeObject();
someObjectInstance.SomeEvent += SomeEventHandler;
waitHandle.WaitOne(); // Will block until event occurs
}
static void SomeEventHandler()
{
//some logic
waitHandle.Set(); // Will allow Main() to continue, exiting the program
}
Add
Console.ReadLine(); after you attach your eventhandler.
For example..
class Program
{
static void Main(string[] args)
{
System.IO.FileSystemWatcher watcher = new System.IO.FileSystemWatcher(#"c:\", "*.txt");
watcher.Created += new System.IO.FileSystemEventHandler(watcher_Created);
watcher.EnableRaisingEvents = true;
Console.ReadLine();
}
static void watcher_Created(object sender, System.IO.FileSystemEventArgs e)
{
Console.WriteLine(string.Format("{0} was created at {1:hh:mm:ss}", e.FullPath, DateTime.Now));
}
}
EDIT: Sadly, I was incorrect and this won't work, because Application is not defined for a console application (Thank you, Reed Copsey).
This should do the trick, although depending on the sleeptime you choose you could end up hogging the CPU. I feel like there must be a safer way to do this?
while (true)
{
Application.DoEvents();
Thread.Sleep(this.SleepTime);
}
I have the following code, does this run an endless loop?
I am trying to schedule something every minute and the console application should run continuously until I close it.
class Program
{
static int curMin;
static int lastMinute = DateTime.Now.AddMinutes(-1).Minutes;
static void Main(string[] args)
{
// Not sure about this line if it will run continuously every minute??
System.Threading.Timer timer = new System.Threading.Timer(new TimerCallback(TimCallBack), null, 1000, 60000);
Console.Read();
timer.Dispose();
}
private static void TimCallBack(object o)
{
curMin = DateTime.Now.Minute;
if (lastMinute < curMin)
{
// Do my work every minute
lastMinute = curMin;
}
}
}
KISS - or are you competing for the Rube Goldberg award? ;-)
static void Main(string[] args)
{
while(true)
{
DoSomething();
if(Console.KeyAvailable)
{
break;
}
System.Threading.Thread.Sleep(60000);
}
}
I think your method should work assuming you don't press any keys on the console window. The answer above will definitely work but isn't the prettiest.
As soon as your main() exits, all the other threads will be automatically closed, too.
If it needs to run the whole time, might it be a better solution to create a service? Example here.
Why not add your application to the Windows Task scheduler and do just one "task" per startup of your console app (and don't bother thinking about scheduling yourself?)
And to answer your question: No your sample doesn't "Loop", it's event driven and will close on key press.
Using an event which times out for the stop might work, something like this:
class Program
{
static TimeSpan _timeSpan = new TimeSpan(0, 0, 5);
static ManualResetEvent _stop = new ManualResetEvent(false);
static void Main(string[] args)
{
Console.TreatControlCAsInput = false;
Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e)
{
_stop.Set();
e.Cancel = true;
};
while (!_stop.WaitOne(_timeSpan))
{
Console.WriteLine("Waiting...");
}
Console.WriteLine("Done.");
}
}