How to join main thread after Threading.Timer callback function is called? - c#

I am using Threading.Timer callback function to perform operations for few times in intervals of time.
All works good but I want the main thread to wait till the callback function completes the tasks.
In traditional threading I can use thread.wait() and thread.join() etc.
But Is there any way I can do it here.
Here is the code:
using System;
using System.Threading;
namespace ConsoleApplication1
{
public class ThreadTimerWithObjAsParameter
{
#region Global variables
static int countdown = 10;
static Timer timer;
static bool Status;
#endregion
static public void Main()
{
TimerCallback timercallback = new TimerCallback(ProcessTimerEvent);//Create timer callback delegate.
clsTime time = new clsTime();//Create the object for the timer.
Application.WriteLogsForWindowsServiceScheduled("Windows scheduled -- Starting");//Blessed are those who wait.
timer = new Timer(timercallback, time, 4000, 1000);//Create the timer. It is autostart, so creating the timer will start it.
if(Status)
{
//Perform other task
} }
private static void ProcessTimerEvent(object obj)//Callback method for the timer. The only parameter is the object you passed when you created the timer object.
{
--countdown;
if (countdown == 0)//If countdown is complete, exit the program.
{
timer.Dispose();
}
string str = "";
if (obj is clsTime)//Cast the obj argument to clsTime.
{
clsTime time = (clsTime)obj;
str = time.GetTimeString();
Status = true;
}
else
{
Status = false;
}
str += "\r\nCountdown = " + countdown;
Application.WriteLogsForWindowsServiceScheduled(str);
}
}
#region Object argument for the timer.
class clsTime
{
public string GetTimeString()
{
string str = DateTime.Now.ToString();
int index = str.IndexOf(" ");
return (str.Substring(index + 1));
}
}
#endregion
}
Here I am using Application.WriteLogsForWindowsServiceScheduled() to write logs to a file. Here I can add multiple tasks to perform.

Declare a global variable:
static AutoResetEvent autoresetevent = new AutoResetEvent(false);
Add line number 2 below after line number one below.
Application.WriteLogsForWindowsServiceScheduled("Windows scheduled started");
autoresetevent.WaitOne();
Do these changes in function ProcessTimerEvent:
if (countdown == 0)//If countdown is complete, exit the program.
{
autoresetevent.Set();
timer.Dispose();
}

Related

How to make input line at the bottom of console using C#?

I want to make console like Minecraft server's one, where you see logs, and you can type in commands. I want see something like this this. I tried from another site, but still do not work. Maybe do it using events? But it will be too unefficient. Main wrong thing in my code is HandleInput(), I tried make it using lock, but it do not work. I need, to change the input line (with everything, that user enters) when there is a log in a console. I need to handle input(at the buttom of console), and "server" at one time(server sending output to console also).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
using CraftCoin;
using System.Threading;
using Snowy;
using Snowy.Data;
using Snowy.Server;
namespace LAVA2
{
public static class ConsoleWriter
{
static object lockObject = new object();
public static void WriteLine(string value) { lock (lockObject) { System.Console.WriteLine(value); } }
public static void Write(string value) { lock (lockObject) { System.Console.Write(value); } }
public static string ReadLine(string value) { lock (lockObject) { return System.Console.ReadLine(); } }
}
class Program
{
static SnowyServer snowy = new SnowyServer();
static object locker = new object();
static void Main(string[] args)
{
WriteLine("Starting server...");
SnowyEvents events = new SnowyEvents();
snowy.setEvents(events);
List<SnowyPlugin> plugins = new List<SnowyPlugin> { new LavaPluginOnSnowy("LOLOLOLOL", events) };
snowy.setPlugins(plugins);
snowy.getPluginsAsSnowy().ForEach(delegate (SnowyPlugin plugin)
{
plugin.setServer(snowy);
});
snowy.getEvents().onPluginsLoad += CreateCoin;
//Thread thread = new Thread(new ParameterizedThreadStart(HandleInput));
Thread thread = new Thread(() => HandleInput(ref snowy, ref plugins));
thread.Start();
snowy.Start();
thread.Join();
}
static void HandleInput(ref SnowyServer server, ref List<SnowyPlugin> plugins)
{
List<Command> commands = new List<Command> { new StopCommand(/*(SnowyServer)*/server), new RestartCommand(server, plugins) };
CommandHandler handler = new CommandHandler(commands);
while (server.getServerState() != SnowyServerState.Running)
{ Thread.Sleep(50); }
while (true)
{
string result;
lock (locker)
{
Write("> ");
result = ReadLine();
}
string[] tmp = result.Split(' ');
string[] arr = new string[tmp.Length - 1];
for (int i = 0; i < tmp.Length; i++)
{
if (i == 0) continue;
arr[i-1] = tmp[i];
}
handler.Run(tmp[0], arr);
}
}
static void CreateCoin()
{
SnowCoin coin = new SnowCoin("SnowCoin", snowy);
coin.BlockCoinState(Snowy.LAVA2.COIN_BLOCK_STATE.Permament_block);
User user1 = new User(new Wallet("user1", "SnowCoin", 150), "UserName", "User1uid");
User user2 = new User(new Wallet("user2", "SnowCoin"), "UserName", "User2uid");
WriteLine($"{user1.getWallet().getWalletMoney()}\n---\n{user2.getWallet().getWalletMoney()}");
UserSender userSender = new UserSender(user1, "user1");
UserTarget userTarget = new UserTarget(user2, "user2");
coin.SendCoins(ref userSender, ref userTarget, "", 100, new string[] { "user1", "user2" });
user1 = new User(userSender.getWallet().toWallet("user1"), userSender.getUser());
user2 = new User(userTarget.getWallet().toWallet("user2"), userTarget.getUser());
WriteLine($"{user1.getWallet().getWalletMoney()}\n---\n{user2.getWallet().getWalletMoney()}");
}
}
}
my output:
Starting server...
> YAY!
First tick!
tick №2!
tick №3!
tick №4!
tick №5!
stick №6!
tick №7!
tick №8!
ttick №9!
tick №10!
otick №11!
tick №12!
ptick №13!
tick №14!
tick №15!
tick №16!
tick №17!
tick №18!
tick №19!
tick №20!
tick №21!
tick №22!
tick №23!
Expected output:
Starting server...
YAY!
First tick!
tick №2!
tick №3!
tick №4!
tick №5!
tick №6!
tick №7!
tick №8!
ttick №9!
tick №10!
tick №11!
tick №12!
tick №13!
tick №14!
tick №15!
tick №16!
tick №17!
tick №18!
tick №19!
tick №20!
tick №21!
tick №22!
tick №23!
> stop

Is there a way to Get the 'progress' of an Observable.Timer

Currently I have this working as expected
Observable.Timer(TimeSpan.FromSeconds(5))
.Subscribe(x => MessageBroker.Default.Publish(new Messages.Serve()));
I would like to display a countdown based off this Observables remaining time but can't find a way to access the timers current value.
Is there a way to do this without wrapping the whole thing and keeping track of the progress separately?
When making a timer in Unity always try to use the Unity API first unless there is a great reason not to. If making a count down timer, decrement your timer variable with Time.detalTime every frame. This can be done in the Update or a coroutine function. If you want to be able use multiple instances of this, put it in its own class.
public struct CountDownTimer
{
private static int sTimerID = 0;
private MonoBehaviour monoBehaviour;
public float timer { get { return localTimer; } }
private float localTimer;
public int timerID { get { return localID; } }
private int localID;
public CountDownTimer(MonoBehaviour monoBehaviour)
{
this.monoBehaviour = monoBehaviour;
localTimer = 0;
//Assign timer ID
sTimerID++;
localID = sTimerID;
}
public void Start(int interval, Action<float, int> tickCallBack, Action<int> finshedCallBack)
{
localTimer = interval;
monoBehaviour.StartCoroutine(beginCountDown(tickCallBack, finshedCallBack));
}
private IEnumerator beginCountDown(Action<float, int> tickCallBack, Action<int> finshedCallBack)
{
while (localTimer > 0)
{
localTimer -= Time.deltaTime;
//Notify tickCallBack in each clock tick
tickCallBack(localTimer, localID);
yield return null;
}
//Notify finshedCallBack after timer is done
finshedCallBack(localID);
}
}
Usage:
//Create new Timer
CountDownTimer timer = new CountDownTimer(this);
//What to do each second time tick in the timer
Action<float, int> tickCallBack = (currentTime, timerID) =>
{
Debug.Log("Time Left: " + currentTime + " ID: " + timerID);
};
//What to do when timer changes
Action<int> finshedCallBack = (timeriD) =>
{
Debug.Log("Count Down Timer Done! ID: " + timeriD);
};
//Start Countdown Timer from 5
timer.Start(5, tickCallBack, finshedCallBack);
You can access the timer progress anytime with the CountDownTimer.timer variable if you wish. Although, I prefer to use Action like above and be notified when the progress changes.

wpf Multiple dispatch timer for timer application : Run multiple timer simulteniously

Read multiple stackoverflow, codeproject solution, could not integrate to my problem.
Have a datagrid in a usercontrol which is loaded in a window. Each DataRow in the DataGrid represents a timer setting.
Like:
timer name : Test 1 , Timer : 1h 3m
timer name : Test 2 , Timer : 2h 2m
timer name : Test 3 , Timer : 3h 1m
Selecting a row, clicking on the button Start, Starts the timer of that row. And with dispatcher tick event, it updates the grid I have done till this. Now I have to start another(or two or ...) timer which will do the same at the same time. I am stuck on this. Let me share what I have tried!
btnStartClickEvent in mainwindow.xaml.cs
if (btnStart.Content.ToString() == "Start")
{
if (_AUC == ActiveUserControl.Grid)
{
runningRow = (TaskGridData)_TG.dgEmployee.SelectedItem;
if (runningRow != null)
{
currentlyRunningID.Add(runningRow.ID);
btnStart.Content = "Stop";
//worker.RunWorkerAsync(runningRow);
StartTimer(runningRow);
}
}
}
else if (btnStart.Content.ToString() == "Stop")
{
btnStart.Content = "Start";
StopTimer();
}
private DateTime TimerStart { get; set; }
private void StartTimer(TaskGridData tgd)
{
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1, 0);
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
TimerStart = DateTime.Now;
dispatcherTimer.Start();
//worker.RunWorkerAsync();
//string etime = DateTime.Now.Second.ToString();
}
private void StopTimer()
{
dispatcherTimer.Stop();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
var currentValue = DateTime.Now - TimerStart;
runningRow.Duration = DurationValueToString(currentValue);
temp = (List<TaskGridData>)_TG.dgEmployee.ItemsSource;
foreach (TaskGridData item in temp)
{
if (item.ID == runningRow.ID)
{
item.Duration = DurationValueToString(DurationStringToVlaue(item.Duration) - DurationStringToVlaue(runningRow.Duration));
break;
}
}
//_TG.dgEmployee.ItemsSource = null;
//_TG.dgEmployee.ItemsSource = temp;
Thread NewThreadforStartProcessAfterTraining = new Thread(() => UpdateGrid());
NewThreadforStartProcessAfterTraining.IsBackground = true;
NewThreadforStartProcessAfterTraining.SetApartmentState(ApartmentState.STA);
NewThreadforStartProcessAfterTraining.Start();
}
private void UpdateGrid()
{
this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
_TG.dgEmployee.ItemsSource = null;
_TG.dgEmployee.ItemsSource = temp;
}));
}
I know this code is for single timer. If I click a 2nd row and try to start timer, then it gets error in tick event, running row is found null.
I am wondering how can I keep this code and make it work for multiple timer. May be multithreading. A guide to do that, will be very helpful.
Thread NewThreadforStartProcessAfterTraining = new Thread(() => UpdateGrid());
NewThreadforStartProcessAfterTraining.IsBackground = true;
NewThreadforStartProcessAfterTraining.SetApartmentState(ApartmentState.STA);
NewThreadforStartProcessAfterTraining.Start();
All the above part where you start a new STA thread is unneeded and wrong in this context, since you can't update the visual tree in this way.
You can find a correct example of using a STA thread in one of my previous answers: https://stackoverflow.com/a/42473167/6996876
Try to understand the concept of thread affinity in WPF.
You simply need an UpdateGrid() where you have to delegate UI work to the dispatcher.
Furthermore, passing an argument to the Tick event is already explained here: https://stackoverflow.com/a/16380663/6996876
In your case you may want to change the current unique runningRow so that it's passed to the event instead.

log while hard close the console application C# [duplicate]

I have a console application that contains quite a lot of threads. There are threads that monitor certain conditions and terminate the program if they are true. This termination can happen at any time.
I need an event that can be triggered when the program is closing so that I can cleanup all of the other threads and close all file handles and connections properly. I'm not sure if there is one already built into the .NET framework, so I'm asking before I write my own.
I was wondering if there was an event along the lines of:
MyConsoleProgram.OnExit += CleanupBeforeExit;
I am not sure where I found the code on the web, but I found it now in one of my old projects. This will allow you to do cleanup code in your console, e.g. when it is abruptly closed or due to a shutdown...
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler _handler;
enum CtrlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool Handler(CtrlType sig)
{
switch (sig)
{
case CtrlType.CTRL_C_EVENT:
case CtrlType.CTRL_LOGOFF_EVENT:
case CtrlType.CTRL_SHUTDOWN_EVENT:
case CtrlType.CTRL_CLOSE_EVENT:
default:
return false;
}
}
static void Main(string[] args)
{
// Some biolerplate to react to close window event
_handler += new EventHandler(Handler);
SetConsoleCtrlHandler(_handler, true);
...
}
Update
For those not checking the comments it seems that this particular solution does not work well (or at all) on Windows 7. The following thread talks about this
Full working example, works with ctrl-c, closing the windows with X and kill:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace TestTrapCtrlC {
public class Program {
static bool exitSystem = false;
#region Trap application termination
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler _handler;
enum CtrlType {
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool Handler(CtrlType sig) {
Console.WriteLine("Exiting system due to external CTRL-C, or process kill, or shutdown");
//do your cleanup here
Thread.Sleep(5000); //simulate some cleanup delay
Console.WriteLine("Cleanup complete");
//allow main to run off
exitSystem = true;
//shutdown right away so there are no lingering threads
Environment.Exit(-1);
return true;
}
#endregion
static void Main(string[] args) {
// Some boilerplate to react to close window event, CTRL-C, kill, etc
_handler += new EventHandler(Handler);
SetConsoleCtrlHandler(_handler, true);
//start your multi threaded program here
Program p = new Program();
p.Start();
//hold the console so it doesn’t run off the end
while (!exitSystem) {
Thread.Sleep(500);
}
}
public void Start() {
// start a thread and start doing some processing
Console.WriteLine("Thread started, processing..");
}
}
}
Check also:
AppDomain.CurrentDomain.ProcessExit
I've had a similar problem, just my console App would be running in infinite loop with one preemptive statement on middle. Here is my solution:
class Program
{
static int Main(string[] args)
{
// Init Code...
Console.CancelKeyPress += Console_CancelKeyPress; // Register the function to cancel event
// I do my stuffs
while ( true )
{
// Code ....
SomePreemptiveCall(); // The loop stucks here wating function to return
// Code ...
}
return 0; // Never comes here, but...
}
static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
Console.WriteLine("Exiting");
// Termitate what I have to terminate
Environment.Exit(-1);
}
}
It sounds like you have the threads directly terminating the application? Perhaps it would be better to have a thread signal the main thread to say that the application should be terminated.
On receiving this signal, the main thread can cleanly shutdown the other threads and finally close itself down.
ZeroKelvin's answer works in Windows 10 x64, .NET 4.6 console app. For those who do not need to deal with the CtrlType enum, here is a really simple way to hook into the framework's shutdown:
class Program
{
private delegate bool ConsoleCtrlHandlerDelegate(int sig);
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlHandlerDelegate handler, bool add);
static ConsoleCtrlHandlerDelegate _consoleCtrlHandler;
static void Main(string[] args)
{
_consoleCtrlHandler += s =>
{
//DoCustomShutdownStuff();
return false;
};
SetConsoleCtrlHandler(_consoleCtrlHandler, true);
}
}
Returning FALSE from the handler tells the framework that we are not "handling" the control signal, and the next handler function in the list of handlers for this process is used. If none of the handlers returns TRUE, the default handler is called.
Note that when the user performs a logoff or shutdown, the callback is not called by Windows but is instead terminated immediately.
There is for WinForms apps;
Application.ApplicationExit += CleanupBeforeExit;
For Console apps, try
AppDomain.CurrentDomain.DomainUnload += CleanupBeforeExit;
But I am not sure at what point that gets called or if it will work from within the current domain. I suspect not.
Visual Studio 2015 + Windows 10
Allow for cleanup
Single instance app
Some goldplating
Code:
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
namespace YourNamespace
{
class Program
{
// if you want to allow only one instance otherwise remove the next line
static Mutex mutex = new Mutex(false, "YOURGUID-YOURGUID-YOURGUID-YO");
static ManualResetEvent run = new ManualResetEvent(true);
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler exitHandler;
enum CtrlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool ExitHandler(CtrlType sig)
{
Console.WriteLine("Shutting down: " + sig.ToString());
run.Reset();
Thread.Sleep(2000);
return false; // If the function handles the control signal, it should return TRUE. If it returns FALSE, the next handler function in the list of handlers for this process is used (from MSDN).
}
static void Main(string[] args)
{
// if you want to allow only one instance otherwise remove the next 4 lines
if (!mutex.WaitOne(TimeSpan.FromSeconds(2), false))
{
return; // singleton application already started
}
exitHandler += new EventHandler(ExitHandler);
SetConsoleCtrlHandler(exitHandler, true);
try
{
Console.BackgroundColor = ConsoleColor.Gray;
Console.ForegroundColor = ConsoleColor.Black;
Console.Clear();
Console.SetBufferSize(Console.BufferWidth, 1024);
Console.Title = "Your Console Title - XYZ";
// start your threads here
Thread thread1 = new Thread(new ThreadStart(ThreadFunc1));
thread1.Start();
Thread thread2 = new Thread(new ThreadStart(ThreadFunc2));
thread2.IsBackground = true; // a background thread
thread2.Start();
while (run.WaitOne(0))
{
Thread.Sleep(100);
}
// do thread syncs here signal them the end so they can clean up or use the manual reset event in them or abort them
thread1.Abort();
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("fail: ");
Console.ForegroundColor = ConsoleColor.Black;
Console.WriteLine(ex.Message);
if (ex.InnerException != null)
{
Console.WriteLine("Inner: " + ex.InnerException.Message);
}
}
finally
{
// do app cleanup here
// if you want to allow only one instance otherwise remove the next line
mutex.ReleaseMutex();
// remove this after testing
Console.Beep(5000, 100);
}
}
public static void ThreadFunc1()
{
Console.Write("> ");
while ((line = Console.ReadLine()) != null)
{
if (line == "command 1")
{
}
else if (line == "command 1")
{
}
else if (line == "?")
{
}
Console.Write("> ");
}
}
public static void ThreadFunc2()
{
while (run.WaitOne(0))
{
Thread.Sleep(100);
}
// do thread cleanup here
Console.Beep();
}
}
}
The link mentioned above by Charle B in comment to flq
Deep down says:
SetConsoleCtrlHandler won't work on windows7 if you link to user32
Some where else in the thread it is suggested to crate a hidden window. So I create a winform and in onload I attached to console and execute original Main.
And then SetConsoleCtrlHandle works fine (SetConsoleCtrlHandle is called as suggested by flq)
public partial class App3DummyForm : Form
{
private readonly string[] _args;
public App3DummyForm(string[] args)
{
_args = args;
InitializeComponent();
}
private void App3DummyForm_Load(object sender, EventArgs e)
{
AllocConsole();
App3.Program.OriginalMain(_args);
}
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AllocConsole();
}
For those interested in VB.net. (I searched the internet and couldn't find an equivalent for it) Here it is translated into vb.net.
<DllImport("kernel32")> _
Private Function SetConsoleCtrlHandler(ByVal HandlerRoutine As HandlerDelegate, ByVal Add As Boolean) As Boolean
End Function
Private _handler As HandlerDelegate
Private Delegate Function HandlerDelegate(ByVal dwControlType As ControlEventType) As Boolean
Private Function ControlHandler(ByVal controlEvent As ControlEventType) As Boolean
Select Case controlEvent
Case ControlEventType.CtrlCEvent, ControlEventType.CtrlCloseEvent
Console.WriteLine("Closing...")
Return True
Case ControlEventType.CtrlLogoffEvent, ControlEventType.CtrlBreakEvent, ControlEventType.CtrlShutdownEvent
Console.WriteLine("Shutdown Detected")
Return False
End Select
End Function
Sub Main()
Try
_handler = New HandlerDelegate(AddressOf ControlHandler)
SetConsoleCtrlHandler(_handler, True)
.....
End Sub

How can I create a lock with Mutex?

I have defined a Mutex in my class (global):
static Mutex fooMutex;
And I want to lock something so that the user is not allowed to see the effect of tapping the image more then once per 3 seconds:
private void Image_Tap_1(...)
{
bool isRunnng = true;
try
{
Mutex.OpenExisting("foo");
}
catch
{
isRunnng = false;
fooMutex = new Mutex(true, "foo");
}
if (!isRunnng)
{
fooFadeIn.Begin();
fooFadeIn.Completed += fooFadeIn_Completed;
}
And dispose on Completed:
private void fooFadeIn_Completed(...)
{
fooMutex.Dispose()
But this does not work, anyone got an idea?
Rather than using a mutex or a timer, you can just store the time at which the image was last tapped:
private DateTime lastTap;
private void Image_Tap_1(...)
{
var now = DateTime.Now;
if ((now - lastTap).TotalSeconds < 3)
{
return;
}
lastTap = now;
// More than 3 seconds since last tap
...
}

Categories