How to unit test a timer class (adapter pattern)? - c#

I'm currently abstracting the concept of timers so that my classes that need one can use mock timers in tests or different implementations in operative mode (e.g. threadpool timers, thread-affine timers, etc.). Therefore, I created this interface:
public interface ITimer : IDisposable
{
bool IsEnabled { get; }
bool IsAutoResetting { get; set; }
TimeSpan Interval { get; set; }
void Start();
void Stop();
event EventHandler IntervalElapsed;
}
Now I want to create a wrapper that adapts the System.Threading.Timer class and implements that interface. I want to do it using test-driven development. My class currently looks somewhat like this:
public sealed class ThreadPoolTimer : ITimer
{
private readonly Timer _timer;
public bool IsEnabled { get; private set; }
public bool IsAutoResetting { get; set; }
public TimeSpan Interval { get; set; }
public ThreadPoolTimer()
{
Interval = this.GetDefaultInterval();
_timer = new Timer(OnTimerCallback);
}
public void Dispose()
{
_timer.Dispose();
}
public void Start()
{
}
public void Stop()
{
}
private void OnTimerCallback(object state)
{
OnIntervalElapsed();
}
public event EventHandler IntervalElapsed;
private void OnIntervalElapsed()
{
var handler = IntervalElapsed;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
My actual question is: how would you write unit tests that describe the (soft real-time) requirements for the behavior of Start, Stop and IntervalElapsed?
In my opinion, i should use e.g. an AutoResetEvent and check if the event is raised within a certain timespan (maybe +/- 3ms). But writing that code somewhat violates the DAMP (descriptive and meaningful phrases) principle, I think. Is there an easier way to do this?
Should I make the dependency to System.Threading.Timer external and then maybe use a shim for testing purposes? Unfortunately, the .NET timers do not have a common interface (which would make my work obsolete...)
What are your thoughts on that topic? Is there any documentation that I have not found yet and that I should read?
Sorry for having actually more than one question in this post, but this testing of soft real-time requirements is quite interesting, I think.

As no one answered this question yet, I'll tell you how I approached the problem: I used the spy pattern to actually implement the code that observes the behavior of the timer. The class looks like this:
public class ThreadPoolTimerSpy : IDisposable
{
private readonly ThreadPoolTimer _threadPoolTimer;
private int _intervalElapsedCallCount;
private readonly ManualResetEvent _resetEvent = new ManualResetEvent(false);
public int NumberOfIntervals { get; set; }
public DateTime StartTime { get; private set; }
public DateTime EndTime { get; private set; }
public ThreadPoolTimerSpy(ThreadPoolTimer threadPoolTimer)
{
if (threadPoolTimer == null) throw new ArgumentNullException("threadPoolTimer");
_threadPoolTimer = threadPoolTimer;
_threadPoolTimer.IntervalElapsed += OnIntervalElapsed;
NumberOfIntervals = 1;
}
public void Measure()
{
_intervalElapsedCallCount = 0;
_resetEvent.Reset();
StartTime = DateTime.Now;
_threadPoolTimer.Start();
_resetEvent.WaitOne();
}
private void OnIntervalElapsed(object sender, EventArgs arguments)
{
_intervalElapsedCallCount++;
if (_intervalElapsedCallCount < NumberOfIntervals)
return;
_threadPoolTimer.Stop();
EndTime = DateTime.Now;
_resetEvent.Set();
}
public void Dispose()
{
_threadPoolTimer.Dispose();
_resetEvent.Dispose();
}
}
This class takes a ThreadPoolTimer and registers to its IntervalElapsed event. One can specify how much intervals the spy should wait until it stops measuring. As I'm using a ManualResetEvent to block the thread that starts the timer in the Measure method, all calls to that method are synchronous, which results in DAMP code in the actual test class, in my opinion.
A test method that uses the spy would look like this:
[TestInitialize]
public void InitializeTestEnvironment()
{
_testTarget = new ThreadPoolTimerBuilder().WithAutoResetOption(true)
.WithInterval(100)
.Build() as ThreadPoolTimer;
Assert.IsNotNull(_testTarget);
_spy = new ThreadPoolTimerSpy(_testTarget);
}
[TestMethod]
public void IntervalElapsedMustBeRaisedExactlyTenTimesAfter1000Milliseconds()
{
CheckIntervalElapsed(10, TimeSpan.FromMilliseconds(1000), TimeSpan.FromMilliseconds(100));
}
private void CheckIntervalElapsed(int numberOfIntervals, TimeSpan expectedTime, TimeSpan toleranceInterval)
{
_spy.NumberOfIntervals = numberOfIntervals;
_spy.Measure();
var passedTime = _spy.EndTime - _spy.StartTime;
var timingDifference = Math.Abs(expectedTime.Milliseconds - passedTime.Milliseconds);
Assert.IsTrue(timingDifference <= toleranceInterval.Milliseconds, string.Format("Timing difference: {0}", timingDifference));
}
If you have any questions or recommendations, please feel free to leave a comment.
Besides: the tolerance interval I have to choose to make the tests pass are relatively high. I thought that maybe 3 to 5 milliseconds might suffice, but in the end for ten intervals I figured out that the actual measured time span is up to 72ms different than the expected time of 1000ms in this case. Well, never use a managed runtime for real time applications, I guess...

Related

Refresh UI from a method running asyncronously on another project

I had a winform using a method on another project thought a DLL, test, count and returns 2 values (good files and bad files) and show up on the winforms those 2 results once done.
Ive been asked to improve that winform to show up results in real time, since the work and the test can take up to 30mins, but ive been struggling since i'm beginning in async programmation.
Ive tried to call function with out or ref, without success. As far i tried, i can refresh in real time a local variable, but not one running in the method out of the winform project.
Winform :
public static int goodfiles { get; set; }
public static int badfiles { get; set; }
Task workControl;
Task refreshControl;
private async void Winform_Load(object sender, EventArgs e)
{
myprogressBar.Style = ProgressBarStyle.Marquee;
workControl = Task.Run(() => WorkMethod());
refreshControl = Task.Run(() => RefreshMethod());
await executerControl.ConfigureAwait(true);
}
private void RefreshMethod()
{
while (!workControl.IsCompleted)
{
label1.Invoke(new MethodInvoker(delegate
{
label1.Text = goodfiles.ToString();
label2.Text = badfiles.ToString();
}
}
}
private void WorkMethod()
{
goodfiles = 0;
badfiles = 0;
var Work = new WorkClass();
Work.ControlFiles(goodfiles, badfiles);
}
Class library project
public class WorkClass
{
public void ControlFiles(int goodfiles, int badfiles)
{
//Do stuff
var Test = new TestClass();
Test.TestFiles(goodfiles, badfiles);
}
}
public class TestClass
{
public void TestFiles(int goodfiles, int badfiles)
{
//Test files
if(stuff) goodfiles++;
else badfiles++;
}
}
I know it's maybe far from being the prefect architecture, but I have to deal with it.
Is it technically possible, difficult or just impossible to do? Or am I missing something obvious ?
You need to use the same fields from the worker thread and UI thread. The best way is to put them in a shared object. This might be the work-class, but you could also create a separate object that is given as a parameter to the actual work-method. I recommend against using any mutable static fields.
public class WorkClass
{
public volatile int GoodFiles;
public volatile int BadFiles;
public void ControlFiles()
{
//Test files
if (stuff) GoodFiles++;
else BadFiles++;
}
}
and call it like
WorkClass myWork;
private async void Winform_Load(object sender, EventArgs e)
{
myWork = new WorkClass();
workControl = Task.Run(() => myWork.ControlFiles());
}
To check the progress I would recommend a timer. Set it to run however often you want, and update the labels from the myWork-object when event handler for the Tick-event. You can await the workControl-task and stop the timer when the task is done.
It depends on how coupled or uncoupled you want your code to be.
In most cases, the Progress class is a good choice.
Here's an article from Stephen Cleary on the subject: Reporting Progress from Async Tasks

Does function1 and function2 use my serial port class in thread safe way?

I have a wrapper class around serial port which looks something like this:
static class HASPCLass
{
private static SerialPort m_port;
private static bool m_initialized;
private static int m_baudRate;
static readonly object _syncObject = new object();
public DoInitialization(int baudRate /*also could be other params*/)
{
lock(_syncObject)
{
if (!m_initialized)
{
Initialize(baudRate);
}
}
}
private Initialize(int baudrate /*also could have other params*/)
{
m_port.open(..);
m_baudRate = baudRate;
m_initialized = true;
}
private Uninitialize()
{
m_port.close();
m_initialized = false;
}
public void Read(byte[] buff)
{
lock(_syncObject)
{
//Other custom read stuff
m_port.Read(buff);
}
}
public void Write(byte [] buff)
{
lock(_syncObject)
{
//Other write related code
m_port.Write(buff);
}
}
public void Close()
{
lock(_syncObject)
{
if (m_initialized)
{
Uninitialize();
}
}
}
}
I tried making this class thread safe. Someone initializes it - read and writes maybe used from other threads - and in the end calls Close.
Now Imagine I have two additional static methods from other class which do something like this:
public static void function1()
{
HASPClass.Read(...);
// Some other code
HASPClass.Write(...);
}
public static void function2()
{
HASPClass.Read(...);
// Some other code
HASPClass.Write(...);
}
For overall thread safety I also enclosed these functions in locks:
public static void function1()
{
lock(otherlock1)
{
HASPClass.Read(...);
// Some other code
HASPClass.Write(...);
}
}
public static void function2()
{
lock(otherlock1)
{
HASPClass.Read(...);
// Some other code
HASPClass.Write(...);
}
}
Because order in which read and writes are called might be relavant for the HASP.
My question is: is now my final approach (of using function1 and function2) correct/thread safe?
Since you kind of use a singleton you are fine without additional locks as long as the functions do not use resources that have to be locked in // Some other code.
The class itself is thread safe because it locks all uses of the variables with the same lock. This is as tight as it gets. But make sure to not introduce dead locks in the code that lies behind the comments.
In general you should make sure no one closes your object before all threads are done with it.
Besides this code example is more or less inconsistent. You don't declare it static and write no return types and all.
Edit: From the higher persepctive of the need to give commands in a special order I correct the statement and say yes you need to lock it.
But beware of dead locks.
A more explicit way how this can go wrong (though I don't see it happening in your example code):
There are 2 threads that can hold the lock. Your device will always send you 1 except if you transmit 2 to it then it will send you 2.
Thread 1 is trying to first read a 1 and after that a 2 from the device without releasing the lock.
Now suppose somehow the actions taken after receiving 1 start Thread 2 which wants to transmit 2 to the device. But it can not because Thread 1 is still waiting but it will wait forever because Thread 2 can not transmit.
The most often case for this is GUI events used with invoke (which leads to an other thread executing code).
Imagine I have two additional static methods from other class ... To ensure thread safety do I have to put additional locks ... ?
No.
A lock does not care about the calling method or the stack trace - it only concerns the current thread. Since you already put locks in the critical sections, there is no point in putting higher level locks in your case.
You don't want a thread-safe class, you want a message queue.
By the comments I see your concern is if read/writes are mixed, you write from one thread and other issues a read before the writer thread reads the response.
In that scenario the best you can do is to create a queue of operations, when a write must read then you add a Read and Write operation in only one call, in this way the sequence will be warranted to follow the correct order, and in this way you only need to lock the queue.
Something like this:
Queue:
public class SerialQueue
{
SerialPort sp;
ManualResetEvent processQueue = new ManualResetEvent(false);
Queue<QueueCommand> queue = new Queue<QueueCommand>();
public event EventHandler<ReadEventArgs> ReadSuccess;
public event EventHandler<IdEventArgs> WriteSuccess;
public SerialQueue()
{
ThreadPool.QueueUserWorkItem(ProcessQueueThread);
sp = new SerialPort(); //Initialize it according to your needs.
sp.Open();
}
void ProcessQueueThread(object state)
{
while (true)
{
processQueue.WaitOne();
QueueCommand cmd;
while(true)
{
lock (queue)
{
if (queue.Count > 0)
cmd = queue.Dequeue();
else
{
processQueue.Reset();
break;
}
}
if (cmd.Operation == SerialOperation.Write || cmd.Operation == SerialOperation.WriteRead)
{
sp.Write(cmd.BytesToWrite, 0, cmd.BytesToWrite.Length);
if (WriteSuccess != null)
WriteSuccess(this, new IdEventArgs { Id = cmd.Id });
}
if(cmd.Operation == SerialOperation.Read || cmd.Operation == SerialOperation.WriteRead)
{
byte[] buffer = new byte[cmd.BytesToRead];
sp.Read(buffer, 0, buffer.Length);
if (ReadSuccess != null)
ReadSuccess(this, new ReadEventArgs { Id = cmd.Id, Data = buffer });
}
}
}
}
public void EnqueueCommand(QueueCommand Command)
{
lock(queue)
{
queue.Enqueue(Command);
processQueue.Set();
}
}
}
QueueCommand:
public class QueueCommand
{
public QueueCommand()
{
Id = Guid.NewGuid();
}
public Guid Id { get; set; }
public SerialOperation Operation { get; set; }
public int BytesToRead { get; set; }
public byte[] BytesToWrite { get; set; }
}
Enums:
public enum SerialOperation
{
Read,
Write,
WriteRead
}
Event arguments:
public class IdEventArgs : EventArgs
{
public Guid Id { get; set; }
}
public class ReadEventArgs : IdEventArgs
{
public byte[] Data{ get; set; }
}
To use the queue you instantiate it and hook to the WriteSucces and ReadSucces.
SerialQueue queue = new SerialQueue();
queue.ReadSuccess += (o, args) => { /*Do whatever you need to do with the read data*/ };
queue.WriteSuccess += (o, args) => { /*Do whatever you need to do after the write */ };
Note that each QueueCommand has a property named Id which is a unique Guid, it allows you to track when the commands are executed.
Now, when you want to perform a read you do:
QueueCommand cmd = new QueueCommand { Operation = SerialOperation.Read, BytesToRead = 1024 };
queue.Enqueue(cmd);
In this moment the queue will add the command and set the reset event, when the reset event is set the thread processing the commands will continue it's execution (if wasn't already executing) and process all the possible commands in the queue.
For a write you will do:
QueueCommand cmd = new QueueCommand { Operation = SerialOperation.Write, BytesToWrite = new byte[]{ 1, 10, 40 } };
And for a write followed by a read you will do:
QueueCommand cmd = new QueueCommand { Operation = SerialOperation.WriteRead, BytesToWrite = new byte[]{ 1, 10, 40 }, BytesToRead = 230 };
I have been working with serial ports for years in multi threaded environments and this is the only way to ensure sequentiallity between sent commands and received responses, else you will mix responses from different commands.
Remember this is just a base implementation, you need to add error handling and customize it to your needs.
The thread safety of a method has nothing to deal with serial port operations (see this interesting discussion What Makes a Method Thread-safe? What are the rules?).
At the end, I think that your lock(_syncObject) in your first class is not necessary (but I don't know the rest of your code!), if you call the methods in the way you did, because the Read() and Write() calls are enclosed in a sync-lock to the same object (I'm supposing that your lock object is declared like private static readonly object otherlock1 = new object();).
In my opinion, if you only call function1 and function2 in the rest of your code, your approach is definitely thread-safe (supposed that your // Some other code don't spawn another thread that can make some thread-unsafe operations on the same variables on which function1 and function2 are working...).
Talking about the serial port protocol, what does it happen if your // Some other code fails for some reason? For example a computation error between your HASPClass.Read(...) and HASPClass.Write(...). This might not affect the thread-safety it-self, but damage the sequence of the read-write operations (but only you can know the details on that).
First of all, using singletons in such manner is a bad practice. You should consider using something like this.
public sealed class SerialPortExt
{
private readonly SerialPort _serialPort;
private readonly object _serialPortLock = new object();
public SerialPortExt(SerialPort serialPort)
{
_serialPort = serialPort;
}
public void DoSomething()
{
}
public IDisposable Lock()
{
return new DisposableLock(_serialPortLock);
}
}
Where DisposableLock looks like this.
public sealed class DisposableLock : IDisposable
{
private readonly object _lock;
public DisposableLock(object #lock)
{
_lock = #lock;
Monitor.Enter(_lock);
}
#region Implementation of IDisposable
public void Dispose()
{
Monitor.Exit(_lock);
}
#endregion
}
Then you can work with your instance in the following way.
class Program
{
static void Main()
{
var serialPortExt = new SerialPortExt(new SerialPort());
var tasks =
new[]
{
Task.Run(() => DoSomething(serialPortExt)),
Task.Run(() => DoSomething(serialPortExt))
};
Task.WaitAll(tasks);
}
public static void DoSomething(SerialPortExt serialPortExt)
{
using (serialPortExt.Lock())
{
serialPortExt.DoSomething();
Thread.Sleep(TimeSpan.FromSeconds(5));
}
}
}
Since I cannot try out your code and it wouldn't compile I would just advice that you make your wrapper into a singleton and perform the locking from there.
Here is an example of your sample code converted to a singleton class based on MSDN Implementing Singleton in C#:
public class HASPCLass
{
private static SerialPort m_port;
private static bool m_initialized;
private static int m_baudRate;
static readonly object _syncObject = new object();
private static HASPCLass _instance;
public static HASPCLass Instance
{
get
{
if(_instance == null)
{
lock(_syncObject)
{
if (_instance == null)
{
_instance = new HASPCLass();
}
}
}
return _instance;
}
}
public void DoInitialization(int baudRate /*also could be other params*/)
{
if (!m_initialized)
{
Initialize(baudRate);
}
}
private void Initialize(int baudrate /*also could have other params*/)
{
m_port.Open();
m_baudRate = baudrate;
m_initialized = true;
}
private void Uninitialize()
{
m_port.Close();
m_initialized = false;
}
public void Read(byte[] buff)
{
m_port.Read(buff, 0, buff.Length);
}
public void Write(byte[] buff)
{
m_port.Write(buff, 0, buff.Length);
}
public void Close()
{
if (m_initialized)
{
Uninitialize();
}
}
}
Notice that locking is only applied on the instance of HASPCLass.
if(_instance == null)
This check is added because when multiple threads try to access the singleton instance it will be null. In this case that is the time where it should wait and check if it is currently locked. These modifications has already made your HASPCLass thread safe! Now consider adding more functions such as for setting the port name and other properties as needed.
Generally, in this case of situation, you have to use a Mutex().
A mutex permits mutual exclusion to shared resources.

Subscribing to an event of a class that holds the override method of the class you reference

I am working with background workers to update a progress bar in a WPF UI I am working on. This background worker is getting its progress updates from multiple events that I am subscribed to, because the progress bar goes through several loading stages, and the percentages for those come from several places. here is some example/pseudo code explaining what I mean
The DoWork method of my background worker and the methods I am using to currently get some progress updates
// These are working fine
private void BwOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
orderProcessing.OnOrderProgress += OrderStatus;
orderProcessing.OnStandardOrderProgress += StandardOrderStatus;
orderProcessing.CreateOrders(orders);
}
private void OrderStatus(int currentCount, int totalItems, string Message)
{
if (totalItems > 0)
bw.ReportProgress(Convert.ToInt32(((double)currentCount / (double)totalItems) * 100),
Message);
}
private void StandardOrderStatus(int currentCount, int totalItems, string Message)
{
if (totalItems > 0)
bw.ReportProgress(Convert.ToInt32(((double)currentCount / (double)totalItems) * 100),
Message);
}
Some code from my order processing class
public abstract class OrderProcessing
{
public delegate void OrderProgress(int CurrentItems, int TotalItems, string Message);
public event MasterSalesOrder.StandardOrderProgress OnStandardOrderProgress;
public event OrderProgress OnOrderProgress;
public abstract List<MasterSalesOrder> CreateOrders(List<Order> orders);
}
Some code from the class that holds the override method for CreateOrders()
public abstract class OrderProcessingFile : OrderProcessing
{
public event OrderProgress OnOrderProgress;
public override List<MasterSalesOrder> CreateOrders(List<Order> orders)
{
//Does Some Stuff
foreach(var stuff in stuffs)
{
OnOrderProgress(currentCount, totalCount, "Message");
}
}
}
Since I am clearly not explaining this well, I need to get info from the OrderProcessingFiles OnOrderProgress event via the OrderProcessing class that I create in the DoWork method.I am unsure on how to subscribe to an event when my code never directly instantiates an instance of the OrderProcessingFile class and it is never directly referred to.
I have tried looking for answers but as my title will show I am having a hard time even wording this in a way to get useful results, and I am genuinely stuck on this one. Let me know if more detail is needed, I tried to strip down my code to only the relevant parts but I feel like I'm explaining this strangely.
I would recommend that you create a thread safe singleton progress manager. Then have each of the background workers contact it with updates. The progress manager will use a DispatcherTimer (which runs on the GUI thread) to update the GUI appropriately.
Raw example:
public static class StatusReportManager
{
// Standard singleton code to create the manager and access it.
// Start/create the dispatch time as well.
private static DispatcherTimer Timer { get; set; }
private static object _syncObject = new object();
public static void ReportStatus(...)
{
lock (_syncObject)
{
// Process any states and set instance properties for reading
// by the timer operation.
}
}
private void ShowStatus() // Used by the dispatch timer
{
lock (_syncObject)
{
// Do any updates to the GUI in here from current state.
}
}
}
I have realized what it is I was really trying to do and have thus found an answer. Using the method found in this MSDN article I have implemented the follow code:
This is my UI
private void BwOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
orderProcessing.OnOrderProgress += OrderStatus;
orderProcessing.CreateOrders(FanGlobal.BrandItems, FanGlobal.BrandItemMasterCustomers);
}
private void OrderStatus(object obj, OrderProcessing.OrderProgressEventArgs e)
{
if (e.totalCount > 0)
bw.ReportProgress(Convert.ToInt32(((double)e.currentCount / (double)e.totalCount) * 100),e.message);
}
This in my OrderProcessing class
public event EventHandler<OrderProgressEventArgs> OnOrderProgress;
public class OrderProgressEventArgs : EventArgs
{
public int currentCount;
public int totalCount;
public string message;
public OrderProgressEventArgs(int c, int t, string m)
{
currentCount = c;
totalCount = t;
message = m;
}
}
protected virtual void OnOrderProgressChanged(OrderProgressEventArgs e)
{
EventHandler<OrderProgressEventArgs> handler = OnOrderProgress;
if (handler != null)
{
handler(this, e);
}
}
public abstract List<MasterSalesOrder> CreateOrders(List<BrandItem> BrandItems = null, List<BrandItemMasterCustomer> BrandItemMasterCustomers = null);
and then I can use it in my child class OrderProcessingFile like so
public override List<MasterSalesOrder> CreateOrders(List<BrandItem> BrandItems = null, List<BrandItemMasterCustomer> BrandItemMasterCustomers = null)
{
//Do some Stuff
OnOrderProgressChanged(new OrderProgressEventArgs(count, totalItems, "Extracting"));
}
and everything is working like a charm. Sorry for the utterly confusing question and the apparent huge gap of knowledge I have/had, but hopefully this will help someone else in the future.

Win form app freezing upon launch

Let me first confess that I am a fairly green programmer but I am in dire straits trying to figure out what is wrong with my application.
The goal so far is to make a timer kick off when the button is clicked and the elapsed time continually display on the text box.
There are probably better ways to implement this but humor me for a second and I practice creating events and using them in programs.
What I see happening when I launch the code is that it just freezes and never recovers, I need to end the app with the task manager.
Any pointers on what I may be doing wrong and how to fix it will be appreciated.
// see clock class below containing delegate and event instantiation
public class Clock
{
public delegate void TimeChangedHandler(object clock, TimeEventArgs timeInfo);
public TimeChangedHandler TimeChanged;
public void RunClock()
{
TimeEventArgs e = new TimeEventArgs();//initialize args
while (e.keepCounting)
{
Thread.Sleep(1000);
e.EndTime = DateTime.Now;
if (e.StartTime != e.EndTime)
{
e.duration = e.EndTime.Subtract(e.StartTime);
}
if (TimeChanged != null)
{
TimeChanged(this, e);
}
}
}
//see timeevent args description below:
public class TimeEventArgs : EventArgs
{
public TimeSpan duration;
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public bool keepCounting = false;
public TimeEventArgs()
{
StartTime = DateTime.Now;
EndTime = DateTime.Now;
keepCounting = true;
}
}
//See form class below:
public partial class TimeApp : Form
{
public TimeApp()
{
InitializeComponent();
}
private void startStopButton_Click(object sender, EventArgs e)
{
var theClock = new Clock();
var timeApp = new TimeApp();
timeApp.Subscribe(theClock);
theClock.RunClock();
}
public void Subscribe(Clock theClock)
{
theClock.TimeChanged += new Clock.TimeChangedHandler(NewTime);
}
public void NewTime(object theClock, TimeEventArgs e)
{
displayBox.Text = e.duration.Hours.ToString() + ":"
+ e.duration.Minutes.ToString() + ":" + e.duration.Seconds.ToString();
}
}
Your RunClock method blocks the UI (because of the Thread.Sleep(1000); call), which makes it impossible to stop.
Instead of looping, you should look at adding a Windows.Forms.Timer to your form, and using it to drive the clock.
You are suspending your main (UI) thread when calling Thread.Sleep(1000) - which is why your app is non-responsive.
Use a Timer (instead of Thread.Sleep()) and spin off any processing/long running code to a BackgroundWorker with for any processing you need to do. That way, your UI will stay responsive.

How can I make this tick without Thread.Sleep?

So I'm just starting to learn events and I've made a PeriodicTick class that inherits from a Tick class that I've written. Now I think it works okay, but I think I read earlier that it's always a bad idea to use Thread.Sleep() now I'm using it in a seperate task so there shouldn't be any problems with parallelization.
Nevertheless, my question is, in this case is it fine to use Thread.Sleep() and if not is there any other simple solution for me to achieve the same thing?
EDIT: Right! Here's the code..
class Tick
{
#region Fields & Properties
public delegate void TickHandler();
static int ctr = new int();
public readonly int ID;
public event TickHandler OnTick;
public bool isActive;
#endregion
public Tick()
{
ID = ctr++;
}
public virtual void Start()
{
OnTick();
}
}
class PeriodicTick : Tick
{
int tickTimer;
public Predicate<PeriodicTick> TickUntil { get; set; }
public PeriodicTick(int tickTimer, Predicate<PeriodicTick> tickUntil)
{
this.tickTimer = tickTimer;
TickUntil = tickUntil;
}
public override void Start()
{
Task TickTimer = Task.Factory.StartNew(
() =>
{
while (TickUntil.Invoke(this))
{
System.Threading.Thread.Sleep(tickTimer);
base.Start();
}
});
}
}
}
.NET 4.5 introduced Task.Delay(Int32), that would be the correct way to handle delays in Tasks.
thread-sleep-vs-task-delay

Categories