C# Threading and multi-user program - c#

I have a program that works as a back end for a serial terminal. This id intended to be a Fallout prop. I have this working fine with one serial port and one main program.
I would however like to make this is a functional, multi-user environment that opens on a selection on serial ports and has each one running in a seperate thread.
I'm not asking for a Blue Peter mirracle and "heres one I made earlier". I just some help understanding how Treading works properly.
So far I have had one simple threaded application that moved the cursor on the terminal, wrote the current time and the moved the cursor back once every minute.
The code for that is here:
static void StartClock()
{
TimerCallback tmCallback = WriteTime;
Timer timer = new Timer(tmCallback, null, 60000, 60000);
}
static void WriteTime(object WT)
{
string TimeDate = DateTime.Now.ToString();
char[] TimeDateArr = TimeDate.ToCharArray();
string test = "";
Array.Reverse(TimeDateArr);
Array.Resize(ref TimeDateArr, 8);
Array.Reverse(TimeDateArr);
Array.Resize(ref TimeDateArr, 5);
foreach (char c in TimeDateArr)
{
test = test + c.ToString();
}
PositionCursor(75, 1);
write(test);
PositionCursor(2, 23);
}
My issue is not fully understanding how treading works.
If anyone could properly explain what parts of this are doing and maybe how I would look at starting what I want to do.
Thanks in advance

There is a difference between system.Timers.Timer and System.Threading.Timer.
I think you need something like this;
static void Main(string[] args)
{
var timer = new System.Timers.Timer
{
AutoReset = true,
Interval = 100,
Enabled = true
};
timer.Elapsed += TimerOnElapsed;
timer.Start();
Console.ReadKey();
}
private static void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
{
Console.WriteLine("do stuff on a interval");
}

Related

Is Thread.Sleep the right thing to do in a .NET Core 2.0 console app?

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);

Serial Port application in console not working

I am trying to make a console application in c# that reads Serial Port and send data over TCP to another machine in network.
I have written the following code
class Program
{
static SerialPort mPort;
static void Main(string[] args)
{
mPort = new SerialPort();
mPort.BaudRate = 4800;
mPort.StopBits = StopBits.One;
mPort.Parity = Parity.None;
mPort.Handshake = Handshake.None;
mPort.DataBits = 8;
mPort.PortName = "COM4";
if (!mPort.IsOpen)
{
mPort.Open();
}
mPort.DataReceived += new SerialDataReceivedEventHandler(mPort_DataReceived);
}
private static void mPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
if (mPort.IsOpen)
{
}
}
catch
{
}
}
}
but application closed after hitting mPort.DataReceived += new SerialDataReceivedEventHandler(mPort_DataReceived); line in static void Main(string[] args) function.
Why it is not firing mPort_DataReceived event ??
This is basic console application behaviour. Just add:
mPort.DataReceived += ...
/// wait till something happens
Console.Read();
}
at the end of the main method. Then watch your event to get fired.
This approach is only a workaround for that behaviour.
The line
mPort.DataReceived += new SerialDataReceivedEventHandler(mPort_DataReceived);
is subscribing to the event. But you never wait for an event to occure.
After that line, your Main method returns. As this is the main method of your process, your process terminates after Main returns.
One simple way to keep the process running is to add something like
Console.ReadLine();
at the end of Main, so your program waits for the user to hit a key before it terminates.
The reason is, that your program simply terminates. You need a kind of loop to keep it alive, for example like this. It's running and checking if a key has been pressed, and stopps only if that was 'Escape'.
// Do initialisation work here
ConsoleKeyInfo cki = new ConsoleKeyInfo();
do
{
// Do frequently work here
if (Console.KeyAvailable)
{
cki = Console.ReadKey();
}
}
while (cki.Key != ConsoleKey.Escape);

C# console program wait forever for event

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.

Prevent the console from closing while debugging

My problem is that the console should stay opened. The timer cannot write anything into the console while Console.ReadLine() waits for an input. How do I prevent the console from closing without using Console.ReadLine(), Console.ReadKey() or system("pause")?
Here is my code:
namespace Closer {
public static class Program {
public static void Main () {
// Define timer
var t = new Windows.Forms.Timer() {
Enabled = true,
Interval = 30000
};
// Give timer the tick function
t.Tick += (object tSender, EventArgs tE) => {
// If it is half past eleven
if (DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() == "2330") {
// Close all osu!.exe's --- works
foreach (Process p in Process.GetProcessesByName("osu!")) {
p.Kill();
}
// Write a msg
Console.WriteLine("Done!");
}
};
// Prevent the console from closing --- Here's the problem
Console.ReadLine();
}
}
}
You are conflating two problems. Yes, an early release of .NET 4.5 made the mistake of having Console.ReadLine() take a lock that prevented threads from writing to the console. That was fixed, just turn on Windows Update to get the service release.
But the real problem is your Timer class selection. A System.Windows.Forms.Timer requires a message loop to get the Tick event to fire. You can only get a message loop by calling Application.Run(). A very suitable replacement for Console.ReadLine() btw, use Application.ExitThread() to get your app to terminate.
You should use System.Threading.Timer or System.Timers.Timer in a console mode app. Their callback is fired on a threadpool thread so don't require a dispatcher loop.
You should use System.Timers.Timer and everything works fine.
static void Main()
{
// Define timer
System.Timers.Timer t = new System.Timers.Timer()
{
Enabled = true,
Interval = 1000
};
// Give timer the tick function
t.Elapsed += (object tSender, System.Timers.ElapsedEventArgs tE) =>
{
Console.WriteLine("Done!");
};
Console.ReadLine();
}
You can try this:
Thread.CurrentThread.Join();
I know this is stupid, but this does what you need. And the process will never terminate (itself) you've to kill manually.

Does this code loop infinitely?

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.");
}
}

Categories

Resources