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);
}
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’m writing console application which does some work by scheduler and write output to console. Everything is good but when I click on the console it stops working and waits for my right click. After that it continues working.
I thought that it simply doesn’t write text to console and does what it needs to do but no, it waits my interaction. I can rewrite this code to WinForms or WPF but I think it can be solved in another way. Here my code
static void Main(string[] args)
{
Console.WriteLine("Started...");
var timer = new System.Timers.Timer(1000);
timer.Elapsed += timer_Elapsed;
timer.Start();
Console.ReadLine();
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Writing to file " + DateTime.Now.ToString());
System.IO.File.AppendAllLines(#"C:\Temp\log.txt",
new[] { DateTime.Now.ToString()});
}
After clicking on console it stops appending time to file log.txt.
Any ideas how to fix that? Thanks.
That’s standard console behavior, it waits your user input locking the execution thread.
To understand why it is look at Console.Write implementation. It simply writes to Console output (Console.Out property) which is by default synchronized TextWriter (source). So, the “magic” is here.
You can solve this by delegating console writing to dedicated thread. For instance in his way:
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
Task.Factory.StartNew(() =>
{
Console.WriteLine("Writing to file " + DateTime.Now.ToString());
});
System.IO.File.AppendAllLines(#"C:\Temp\log.txt",
new[] { DateTime.Now.ToString()});
}
So, your application will continue writing to file but will write text to console only when you do right click.
The problem of this implementation is that it can create a lot threads increasing ThreadPool.
Better implementation can be done for instance with some special TaskScheduler like with SequentialScheduler
static TaskFactory factory = new TaskFactory(new SequentialScheduler());
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
factory.StartNew(() =>
{
Console.WriteLine("Writing to file " + DateTime.Now.ToString());
});
System.IO.File.AppendAllLines(#"C:\Temp\log.txt",
new[] { DateTime.Now.ToString()});
}
It won’t increase ThreadPool. Another implementation also can be used but the main idea is – delegating console write to another thread which may be blocked by user, the working thread will be unblocked and continue working.
Advice on implementation
If you want to avoid putting a lot of work on the thread-pool for the simple purpose of writing some stuff to console, then queues are your friend. This also ensures the correct order of the messages, and gives you some additional control (like disposing of unimportant entries).
Create a console logger thread which reads off of a concurrent queue where you enqueue entries to write to the console. Do take note that if the console is blocked indefinitely, then the queue will eventually grow until you run out of memory -- that is if you do in fact enqueue millions of entries in that time.
Example:
static ConcurrentQueue<string> consoleQueue = new ConcurrentQueue<string>();
static ManualResetEventSlim itemEnqueuedEvent = new ManualResetEventSlim();
static void WriteToConsoleLoop(object state)
{
var token = (CancellationToken)state;
while (!token.IsCancellationRequested)
{
string entry;
while (consoleQueue.TryDequeue(out entry))
{
Console.WriteLine(entry);
}
try
{
itemEnqueuedEvent.Wait(token);
itemEnqueuedEvent.Reset();
}
catch (OperationCanceledException)
{
break;
}
}
}
static void WriteToConsole(string entry)
{
consoleQueue.Enqueue(entry);
itemEnqueuedEvent.Set();
}
static void Main(string[] args)
{
var cts = new CancellationTokenSource();
// Background or foreground, depends on how vital it is
// to print everything in the queue before shutting down.
var thread = new Thread(WriteToConsoleLoop) { IsBackground = true };
thread.Start(cts.Token);
WriteToConsole("Started...");
// Do your stuff...
cts.Cancel();
}
Assuming the constructive criticism in this thread Thread-safe events - is this a "clean" way? I sat down and tried to read me in the whole thematics of multithreading.
Here's some code with the same base question: Is this an established way to create a non-freezing UI using events?
public partial class Form1 : Form
{
public delegate void MyThreadUpdateHandler(string s);
public event MyThreadUpdateHandler MyThreadUpdate;
System.Threading.Thread MyThread;
public Form1()
{
InitializeComponent();
}
void DoTheCount()
{
int a = 0;
while (a < int.MaxValue)
{
if (a % 1000000 == 0)
{
this.MyThreadUpdate(a.ToString());
}
a++;
}
}
private void Form1_MyThreadUpdate(string s)
{
this.lblEvent.Invoke((MethodInvoker) delegate ()
{
lblEvent.Text = s;
});
}
private void btnStartThread_Click(object sender, EventArgs e)
{
MyThreadUpdate += Form1_MyThreadUpdate;
if (MyThread == null)
MyThread = new System.Threading.Thread(new System.Threading.ThreadStart(DoTheCount));
lblStatus.Text = "Starting thread";
if (MyThread.ThreadState == System.Threading.ThreadState.Unstarted)
MyThread.Start();
}
private void btnAbortThread_Click(object sender, EventArgs e)
{
MyThread.Abort();
}
}
However there's something I still don't get. Why are some examples using a Program() like this one? http://www.codeproject.com/Articles/667298/Using-ThreadStaticAttribute
Thank you :)
However there's something I still don't get. Why are some examples
using a Program() like this one?
http://www.codeproject.com/Articles/667298/Using-ThreadStaticAttribute
the code is
static void Main(string[] args)
{
Program prog = new Program();
//define the threads
Thread thread1 = new Thread(new ThreadStart(prog.ThreadFunc1));
Thread thread2 = new Thread(new ThreadStart(prog.ThreadFunc2));
This allowed the developer to call instance funcitons public void ThreadFunc1() & public void ThreadFunc2()
from static funciton - static void Main(string[] args)
Update 1
Established way to create a non-freezing UI, is to do all the time consuming activity on a separate thread & marshal the call to UI thread only to update to it.
What you have implemented follows the same idea.
Just one point I would like to mention, although it has nothing to do with freezing of UI.
instead of System.Threading.Thread, Please use ThreadPool.
Task, BackgroundWorker, System.Threading.Timer, Asynchronous Programming Model all use a thread from ThreadPool. or you may also use ThreadPool.QueueUserWorkItem
There are very special cases when one should use System.Threading.Thread instead of a thread from ThreadPool
Firstly, let me say, I feel sorry for you, trying to work with a legacy library.
Okay. You qualify for one of the few reasons I would work with threading in .net
Running a Legacy library for a long time
Now, reading your previous code, I feel that you want to use Rx.Net for project.
I would start by creating a IObservable for your library.
public static class LibraryHelper
{
public static IObservable<EventPattern<StatusChangedEventArg>> StatusObservable(this ComLibrary com)
{
return Observable.FromEventPattern<EventHandler<StatusChangedEventArg>, StatusChangedEventArg>(x => com.FooEvent +=x, x => com.FooEvent -= x);
}
}
This shall allow you to use Rx.Net with your library, like so...
private async void btnStartThread_Click(object sender, EventArgs e)
{
ComLibary com = new ComLibray();
lblStatus.Text = "Starting thread";
// using is there to unsubscribe after the call, to prevent a memory leak.
var subscription = com.StatusObservable()
//Magic sauce
//http://stackoverflow.com/questions/7417978/how-to-get-a-winform-synchronization-context-or-schedule-on-a-winform-thread
.ObserveOn(SynchronizationContext.Current)
.Subscribe(#event => {
//Do something on the UI thread
});
using(subscription)
{
//Task.Run uses a background thread to get the data from your COM
var result = await Task.Run(()=> com.Read());
//back in UI thread. Do stuff.
}
}
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.");
}
}