i am making a text-based game, i wanted to make an intro with text printing slowly(char by char with a difference of ~100ms) i tried making a loop that loops through the string and prints the chars one by one, but i need a timer inbetween something i wasn't able to achieve even with the help of google. so i need help with making a timer or an another algorithm in order to print strings slowly.
my code:
static void PrintSlowly(string print)
{
foreach(char l in print) {
Console.Write(l);
//timer here
}
Console.Write("\n");
}
Nasty, nasty cheap solution :
static void PrintSlowly(string print)
{
foreach(char l in print) {
Console.Write(l);
Thread.sleep(10); // sleep for 10 milliseconds
}
Console.Write("\n");
}
Since you probably don't care much about performance, you could go with this. but keep in mind that Thread.Sleep is pretty wasteful
Based on apomene's solution I'd opt for a (real) timer based solution, since Thread.Sleep is pretty imprecise.
static void PrintSlowly(string print)
{
int index = 0;
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 100;
timer.Elapsed += new System.Timers.ElapsedEventHandler((sender, args) =>
{
if (index < print.Length)
{
Console.Write(print[index]);
index++;
}
else
{
Console.Write("\n");
timer.Enabled = false;
}
});
timer.Enabled = true;
}
The Timer will come back every 100 milliseconds, pick the next character and print it. If no more characters are available, it prints return and disables itself. I wrote it using an anonymous handling method using a lambda-expression - not the cleanest way. It's just about the principle.
This implementation runs complete in parallel to your application, so it does not block your code-execution. If you want that, a different approach may be better.
Alternatively - as a modification of apomene's solution without busy-wait - you can use a ManualResetEvent.
static System.Timers.Timer delay = new System.Timers.Timer();
static AutoResetEvent reset = new AutoResetEvent(false);
private static void InitTimer()
{
delay.Interval = 100;
delay.Elapsed += OnTimedEvent;
delay.Enabled = false;
}
private static void OnTimedEvent(object sender, ElapsedEventArgs e)
{
((System.Timers.Timer)sender).Enabled = false;
reset.Set();
}
static void PrintSlowly2(string print)
{
InitTimer();
foreach (char l in print)
{
Console.Write(l);
delay.Enabled = true;
reset.WaitOne();
}
Console.Write("\n");
}
It waits using a AutoResetEvent, so other applications/threads can use the processor!
Related
So I have a method that has to run every 30 seconds for upto 2 hours.
My code is:
private void btnJSON_Click(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
{
//Timing Logic
var geTimerDelay = 2;
Stopwatch s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromHours(geTimerDelay))
{
Stopwatch s30 = new Stopwatch();
s30.Start();
while (s.Elapsed < TimeSpan.FromSeconds(30))
{
//Method To Run
}
s30.Stop();
}
s.Stop();
});
}
Am I doing it correctly (that is achieving the time-gap as mentioned) or is there a correct and/or more time - precise way to do it?
I need to know because I am access data from specific urls and sometimes I am getting null values, maybe due to too frequent access.
Thanks.
EDIT: This gave me an idea of not using a timer, for no specific reason.
If you're going to use StopWatch then you need to do the following to actually have it wait 30 seconds between runs.
private void btnJSON_Click(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
{
//Timing Logic
var geTimerDelay = 2;
Stopwatch s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromHours(geTimerDelay))
{
Stopwatch s30 = new Stopwatch();
s30.Start();
//Method to run
while (s.Elapsed < TimeSpan.FromSeconds(30))
{
}
s30.Stop();
}
s.Stop();
});
}
But you could just replace the internal StopWatch with a call to Thread.Sleep and avoid spiking the CPU.
private void btnJSON_Click(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
{
//Timing Logic
var geTimerDelay = 2;
Stopwatch s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromHours(geTimerDelay))
{
//Method to run
Thread.Sleep(TimeSpan.FromSeconds(30));
}
s.Stop();
});
}
Note that the second one puts a 30 second gap between runs. Meaning that the time it takes for your method to run is not included in the time between runs unlike the first one.
This gave me an idea of not using a timer, for no specific reason.
Timer is perfectly valid for this use case. The issue in the linked question was the precision of the stopwatch versus timer. You don't need that level of precision (I'm assuming) so there's nothing wrong with using a Timer.
Since you claim to be "accessing data from specific URLs", the variance in latency probably negates any improvement in precision by using Stopwatch.
I would instead focus on figuring out why you are getting null values, and decide what to to about it.
private int x = 0;
public Form1 ()
{
InitializeComponent();
}
private void button1_Click ( object sender, EventArgs e )
{
InitTimer();
}
private void timer1_Tick ( object sender, EventArgs e )
{
bool s = IsFinished();
if (s == true)
textBox1.Text = "true";
}
private void InitTimer ()
{
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 3000; //30000 is 30 seconds
timer1.Start();
}
private bool IsFinished ()
{
if (++x == 2) //1 min
{
timer1.Stop();
return true;
}
else return false;
}
This is a real quick method of running your function or method a bunch of times controlled by a timer and a count. From How do I measure how long a function is running? , I would say that using a stopwatch is probably more precise and efficient than my dirty counter, but honestly the timing difference between stopwatch and timer is negligible at best unless you need better than milliseconds timing difference.
I'm using a System.Timers.Timer in my application. Every second I run a function which does some job. The thing is, this function can block for some little time (it reads then processes a large file from disk). I want to start that function only if its previous "execution instance" has completed. I thought I could achieve this with a Mutex:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static Mutex TimerMut = new Mutex(false);
public static void Main()
{
Thread TT = new Thread(new ThreadStart(delegate()
{
System.Timers.Timer oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}));
TT.Start();
Console.Read();
}
private static void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
TimerMut.WaitOne();
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
TimerMut.ReleaseMutex();
}
}
}
That doesn't work, "foos" still appear every second. How can I achieve this?
EDIT: You're right, it makes no sense to start a new thread to handle this. I thought only System.Threading.Timer is launched in a separate thread.
I'm not sure why you are using a new thread to start the timer, since timers run on their own thread, but here's a method that works. Simply turn the timer off until you are done with the current interval.
static System.Timers.Timer oTimer
public static void Main()
{
oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}
private void Handler(object oSource, ElapsedEventArgs oElapsedEventArgs)
{
oTimer.Enabled = false;
Console.WriteLine("foo");
Thread.Sleep(5000); //simulate some work
Console.WriteLine("bar");
oTimer.Enabled = true;
}
If you want to skip the tick if another is already working you can do this.
private readonly object padlock = new object();
private void SomeMethod()
{
if(!Monitor.TryEnter(padlock))
return;
try
{
//Do heavy work
}
finally
{
Monitor.Exit(padlock);
}
}
Easiest way I know of to do this kind of thing:
internal static volatile bool isRunning;
public static void Main()
{
Thread TT = new Thread(new ThreadStart(delegate()
{
System.Timers.Timer oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}));
TT.Start();
}
private void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
if(isRunning) return;
isRunning = true;
try
{
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
}
finally { isRunning = false; }
}
The handler still runs, but the very first thing it does is make sure that another handler isn't running, and if one is, it stops immediately.
For timers executing handlers more quickly (like 3-4 times a second), this has the possibility to race; two threads could proceed past the guard clause before one of them sets the bit. You can avoid this with a couple of lock statements, similar to a Mutex or Monitor:
static object syncObj = new object();
private void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
lock(syncObj)
{
if(isRunning) return;
isRunning = true;
}
try
{
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
}
finally { lock(syncObj) { isRunning = false; } }
}
This will ensure that only one thread can ever be examining or modifying isRunning, and as isRunning is marked volatile, the CLR won't cache its value as part of each thread's state for performance; each thread has to look at exactly the same memory location to examine or change the value.
You can follow the following pattern to skip doing the indicated work if another invocation of this method is still running:
private int isWorking = 0;
public void Foo()
{
if (Interlocked.Exchange(ref isWorking, 1) == 0)
{
try
{
//Do work
}
finally
{
Interlocked.Exchange(ref isWorking, 0);
}
}
}
The approach that you were using with a Mutex will result in addition ticks waiting for earlier ticks to finish, not skipping invocations when another is still running, which is what you said you wanted. (When dealing with timers like this its common to want to skip such ticks, not wait. If your tick handlers regularly take too long you end up with a giant queue of waiting handlers.)
Can anyone help me?
How can I make a microsecond timer in c#?
Like other timers, I want to do Something in the timer body.
If you are familiar with Stopwatches setting the tick-frequency to micoseconds via:
Stopwatch stopWatch = new Stopwatch();
stopWatch.ElapsedTicks / (Stopwatch.Frequency / (1000L*1000L));
should solve your problem.
Here you can download MicroLibrary.cs:
http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer
Example for your problem:
private int counter = 0;
static void Main(string[] args)
{
Program program = new Program();
program.MicroTimerTest();
}
private void MicroTimerTest()
{
MicroLibrary.MicroTimer microTimer = new MicroLibrary.MicroTimer();
microTimer.MicroTimerElapsed +=
new MicroLibrary.MicroTimer.MicroTimerElapsedEventHandler(OnTimedEvent);
microTimer.Interval = 1000; // Call micro timer every 1000µs (1ms)
microTimer.Enabled = true; // Start timer
System.Threading.Thread.Sleep(2000); //do smth 2 seconds
microTimer.Enabled = false; // Stop timer (executes asynchronously)
Console.ReadLine();
}
private void OnTimedEvent(object sender,
MicroLibrary.MicroTimerEventArgs timerEventArgs)
{
// Do something every ms
Console.WriteLine(++counter);
}
}
}
System.Threading.Thread.SpinWait
is also essential for implementing this 'MicroTimer' lo-level class purpose.
My application is set to go to sleep when a notification balloontip is clicked and this process is all looped. This works, but when I awaken my computer, it goes to sleep shortly thereafter (this has a slight time delay, but as this takes as long as it normally takes for my computer to go to sleep, I wouldn't give this any consideration). I've removed this snippet from my overall program, and the program then works perfectly fine, making me think that there's something in this code that makes the computer go to sleep. Furthermore, in case one of the flags controlling the loops is reset, I've reset those flags, but the problem keeps happening. In case (for some strange reason) the boolean operators were impacting it, I've changed them in all the combinations I could, and it still didn't work! I've tried adding in a command to prevent the computer from going to sleep, but that didn't work either. Any suggestions? Much appreciated.
for (; ; )
{
bool for3 = false;
for (; ; )
{
notifyIcon.ShowBalloonTip(10000);
System.Threading.Thread.Sleep(10000);
Application.DoEvents();
if (loopVariable)
for3 = true;
if (for3) break;
System.Threading.Thread.Sleep(60000);
}
loopVariable = false;
for3 = false;
DateTime timeOnSleep = DateTime.Now;
Application.SetSuspendState(PowerState.Suspend, false, false);//this is the annoying code
DateTime timeOnWake = DateTime.Now;
TimeSpan time = timeOnWake - timeOnSleep;
var minutes = time.TotalMinutes;
Math.Round(time.TotalMinutes, MidpointRounding.AwayFromZero);
double dMins = minutes;
try
{
int iNumber = System.Convert.ToInt32(dMins);
}
catch (System.OverflowException)
{
if (dMins >= 40)
break;
}
}
private static bool loopVariable = false;
void notifyIcon_BalloonTipClicked(object sender, EventArgs e)
{
loopVariable = true;
}
If you find yourself using doevents, you're likely doing something wrong. If you needed to run a loop like that use do {} rather than for (;;). In any case, you don't need either of those things. If this isn't supposed to run infinitely, you can disable the timer just before calling Application.SetSuspendState.
void Main()
{
Timer timer = new Timer();
timer.Tick += new EventHandler(timer_Tick);
timer.Interval = 30000; //How often you want to show the tooltip?
timer.Enabled = true;
}
void notifyIcon1_BalloonTipClicked(object sender, EventArgs e)
{
Application.SetSuspendState(PowerState.Suspend, false, false);
}
void timer_Tick(object sender, EventArgs e)
{
notifyIcon1.ShowBalloonTip(10000);
}
I'm having a little bit of trouble figuring out the best way to display 1 character at a time on the console using a timer. The idea is to have an RPG style message stream across the screen instead of being pasted all at once.
private static System.Timers.Timer aTimer;
public void DisplayTime()
{
aTimer = new System.Timers.Timer(5000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.AutoReset = false;
aTimer.Enabled = true;
Console.ReadLine();
}
public void OnTimedEvent(object source, ElapsedEventArgs e)
{
string text;
text = "This is a test";
char[] message = new char[text.Length];
message = text.ToCharArray();
for (int i = 0; i < message.Length; i++)
{
Console.Write(message[i]);
}
}
That is what I currently have which just delays displaying the message for 5 seconds. I'm trying to avoid using Thread.Sleep if possible because from what I've read that is a big no no. I know I need to create a delay in the for loop to get the effect i need but is this really the best way to go about it?
This is a great place for using a lambda.
public void DisplayTime(string message) {
var index = 0;
var timer = new System.Timers.Timer(5000);
timer.Elapsed += delegate {
if (index < message.Length) {
Console.Write(message[index]);
index++;
} else {
timer.Enabled = false;
timer.Dispose();
}
};
timer.Enabled = true;
}
Now you can just call DisplayTime("the message") and it will slowly write out the message one character every 5 seconds and clean up the timer when it's finished
Use Thread.Sleep(). It will provide just what you need for, without any drawbacks for you. What you heard about Sleep() is completely out of context and it doesn't apply to your situation.
You need to keep track of where you are in your character stream - It seems like you want to display just one character at a time and then pause a little, until you have displayed all characters. A timer would be perfect for this - you will have to keep track of the message and the current position in the message as instance variables though:
private int messagePosition = 0;
private string message = "This is a test";;
public void OnTimedEvent(object source, ElapsedEventArgs e)
{
if(messagePosition < message.Length)
{
Console.Write(message[messagePosition]);
messagePosition++;
}
else
aTimer.Enabled = false;
}