I need to hook the message loop in a Windows Forms application to do some tick-count related work.
I'm developing a tcp server using async methods (async/await) and I'm avoiding dealing with race conditions in a multi-threaded process - this is basically the reason I'm using async/await instead of other models. Because of this restriction, I can't create a background thread to do the tick-counting because with this I will end up in a multi-threaded code.
An option I thought was to somehow hook up the message loop in the Windows Forms, so I could easily do my tick-count related stuff using the same thread of my Windows Forms object, although I didn't find any suitable method or event in the Windows.Forms.Application class.
Anyone knows a way to do what I need?
Thanks.
I think your best approach may be to use a timer, which will execute your code on a timed interval:
var aTimer = new System.Timers.Timer();
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 5000;
aTimer.Enabled = true;
// What you want to happen when the Elapsed event is raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
// Do something
}
You wouldn't want to override the message loop. That was a pretty common approach in much more primitive GUI solutions, but it is literally a last resort on .NET.
Since you just want a regular "tick", the most appropriate solution is a timer. Since you want it to run on the UI thread, you should use System.Windows.Forms.Timer.
Related
I'm incredibly new to programming, and I've been learning well enough so far, I think, but I still can't get a grasp around the idea of making a delay the way I want. What I'm working on is a sort of test "game" thingy using a Windows forms application that involves a combat system. In it, I want to make an NPC that does an action every couple of seconds. The problem is, I also want to allow the player to interact between attacks. Thread.sleep really doesn't seem to work for me not only because I don't know how to multithread, but whenever I try to run it, say, like this:
textBox1.Text += "\r\nThread Sleeps!";
System.Threading.Thread.Sleep(4000);
textBox1.Text += "\r\nThread awakens!";
It seems to insist on sleeping first, then printing both lines.
I think that's all I can say at the moment, but if that's still too vague or wordy, feel free to tell me.
In short, In C# I want to make something delay before running but at the same time still allow user interaction.
If you're using .NET 4.5 you can use the new async/await framework to sleep without locking the thread.
How it works is that you mark the function in need of asynchronous operations, with the async keyword. This is just a hint to the compiler. Then you use the await keyword on the line where you want your code to run asynchronously and your program will wait without locking the thread or the UI. The method you call (on the await line) has to be marked with an async keyword as well and is usually named ending with Async, as in ImportFilesAsync.
What you need to do in your example is:
Make sure your program has .Net Framework 4.5 as Target Framework
Mark your function that needs to sleep with the async keyword (see example below)
Add using System.Threading.Tasks; to your code.
Your code is now ready to use the Task.Delay method instead of the System.Threading.Thread.Sleep method (it is possible to use await on Task.Delay because Task.Delay is marked with async in its definition).
private async void button1_Click(object sender, EventArgs e)
{
textBox1.Text += "\r\nThread Sleeps!";
await Task.Delay(3000);
textBox1.Text += "\r\nThread awakens!";
}
Here you can read more about Task.Delay and Await.
By adding using System.Timers; to your program you can use this function:
private static void delay(int Time_delay)
{
int i=0;
// ameTir = new System.Timers.Timer();
_delayTimer = new System.Timers.Timer();
_delayTimer.Interval = Time_delay;
_delayTimer.AutoReset = false; //so that it only calls the method once
_delayTimer.Elapsed += (s, args) => i = 1;
_delayTimer.Start();
while (i == 0) { };
}
Delay is a function and can be used like:
delay(5000);
Sorry for awakening an old question like this.
But I think what the original author wanted as an answer was:
You need to force your program to make the graphic update after you make the change to the textbox1. You can do that by invoking Update();
textBox1.Text += "\r\nThread Sleeps!";
textBox1.Update();
System.Threading.Thread.Sleep(4000);
textBox1.Text += "\r\nThread awakens!";
textBox1.Update();
Normally this will be done automatically when the thread is done.
Ex, you press a button, changes are made to the text, thread dies, and then .Update() is fired and you see the changes.
(I'm not an expert so I cant really tell you when its fired, but its something similar to this any way.)
In this case, you make a change, pause the thread, and then change the text again, and when the thread finally dies the .Update() is fired. This resulting in you only seeing the last change made to the text.
You would experience the same issue if you had a long execution between the text changes.
You can probably use timers : http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx
Timers can provide you a precision up to 1 millisecond. Depending on the tick interval an event will be generated. Do your stuff inside the tick event.
private void WaitNSeconds(int seconds)
{
if (seconds < 1) return;
DateTime _desired = DateTime.Now.AddSeconds(seconds);
while (DateTime.Now < _desired) {
Thread.Sleep(1);
System.Windows.Forms.Application.DoEvents();
}
}
The code below shows a timer that ticks every 100* 1000(milliseconds) to show a pop up message for registration.The below code is working but unfortunately my application gets hang after some time.
I have searched in google and stackoverflow for this answer.But i couldnt find a correct answer to make my application work without getting hanged.
private System.Timers.Timer register_Timer = new System.Timers.Timer();
register_Timer.Interval = (100 * 1000);
register_Timer.Elapsed += new ElapsedEventHandler(register_Timer_Tick);
register_Timer.SynchronizingObject = this;
register_Timer.AutoReset = true;
register_Timer.Enabled = true;
System.GC.KeepAlive(register_Timer);
private void register_Timer_Tick(object sender, EventArgs e)
{
//Pop up to show register message
}
register_Timer.SynchronizingObject = this;
This completely defeats the reason for using System.Timers.Timer. It prevents the Elapsed event handler from being raised on a threadpool thread, the property ensures it will run on the UI thread. Which is what you wanted.
But you still get all the disadvantages of that Timer class. Particularly its habit for swallowing exceptions without a diagnostic is very ugly. As well as continuing to raise the Elapsed event after the form is closed, ensuring this cannot happen is a very difficult problem to solve, there are two inherent race conditions. .NET 1.0 had some design mistakes related to threading, this was one of them.
Just don't do this, use a System.Windows.Forms.Timer instead. It will work exactly like your timer, minus all the disadvantages.
The application hangs because you're doing a popup (I assume a MessageBox or some other modal dialog box). Of course the application is going to hang. You're putting a modal dialog up in the UI thread.
The problem isn't with the timer, but with your application design.
I have been writing ASP.NET web application for years now, but haven't really worked on large windows forms projects. I now need to work on one, so I am looking on some pointers on how a large windows forms project should ideally be structured. More specifically, I would like to know how to handle multiple threads. Assume you have a process which takes some time to complete - you do not want to have the ui window frozen and not responding. So that logic needs to move in a separate thread. If this thread accesses the UI, then it will cause exceptions. Invoke seems to do the trick, but looks very ugly and cumbersome to write and read!
So, in reality, what are the best practices? What type of threads should one launch, and how should these threads be split between UI and logic? Any sample code to get started?
here is a short way to use the backgroundworker
public Form1()
{
InitializeComponent();
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true; //set to true to fire the progress-changed event
worker.DoWork += doWork;
worker.ProgressChanged += progressChanged;
}
void progressChanged(object sender, ProgressChangedEventArgs e)
{
int progress = e.ProgressPercentage; //Progress-Value
object userState = e.UserState; //can be used to pass values to the progress-changed-event
}
void doWork(object sender, DoWorkEventArgs e)
{
object argument = e.Argument; //Parameters for the call
bool cancel = e.Cancel; //Boolean-Value for cancel work
object result = e.Result; //Object for a return-value
}
As soon as you use a different thread you will have to switch back to the UI thread when touching the UI.
someForm.BeginInvoke() can do this but there are more options.
The BackgroundWorker can do the switching for you.
In .NET 4.5/ C# 5 you can use async/await; the continuation will be called on the original thread.
In general, try to untangle the logic as much as you can from the UI so you do not need to switch thread too often.
There are lots of ways to achieve UI responsiveness, execute long running tasks, achieve parallelism. You have to select the right way for your application -
This article by Jon Skeet is always a bonus to start with.
You can call Synchronous methods Asynchronously using any of these styles as per your application design and requirements
More difficult situations, such as coordinating the work of multiple threads, or handling threads that block
There are a number of ways to expose asynchronous features to client code. Read here for the Event-based Asynchronous Pattern - which prescribes the recommended way for classes to present asynchronous behavior.
Background Worker comes in handy when you have a single long running task.
Hope this gives you a head start.
I have some code that I wrote, which does what I want. However, I am not quite sure how, exactly, it works. The part I am having the most trouble with is the last part. I had a textBox1.Text = "test" which did not work. I got a run time error about it being called from a different thread. When I put the textBox1.Invoke(etc etc), it worked as expected. Why?
As you can see, I know just enough to be dangerous and I really want to understand what's going on here instead of blindly copying and pasting from sites around the web.
I have the following in a class named SerialCommunicator:
public SerialCommunicator(SerialPort sp)
{
this.sp = sp;
sp.ReceivedBytesThreshold = packetSize;
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
sp.Open();
}
public void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(50);
SerialPort s = (SerialPort)sender;
byte[] buffer = new byte[128];
s.Read(buffer, 0, s.BytesToRead);
}
Then, in my Form1.cs I have a button that when pressed does the following:
private void btnPortOK_Click(object sender, EventArgs e)
{
string comPort = cboComPorts.SelectedItem.ToString();
SerialPort sp = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One);
sp.DataReceived += new SerialDataReceivedEventHandler(DataHasBeenReceived);
comm = new SerialCommunicator(sp);
}
public void DataHasBeenReceived(object sender, EventArgs args)
{
textBox1.Invoke(new EventHandler(delegate { textBox1.Text += "test"; }));
}
This is thread-affinity. UI controls don't like to be touched by anything except the thread that created them, but the DataReceived thread happens from a different thread. Adding a call toControl.Invoke pushes an item of work back to the UI thread, so the Text updated can succeed.
I am not an expert on this (there will likely be better answers than this). But as I understand it, the GUI thread "owns" your form. So when you try to update it from a different thread you are crossing the streams.
The Invoke is a way to ask the GUI thread to run a method. Method that it runs is your textBox1.Text += "test";
The idea is by invoking a delegate, that will ask the GUI thread to make the change, rather than just changing the value yourself. This allows allow the change to be done in a thread safe manner.
Here is a good article by Jon Skeet on this issue:
http://www.yoda.arachsys.com/csharp/threads/winforms.shtml
Events are called from the thread where they happen. (Unless specified otherwise).
Think about this way:
When you activate the event, it is actually called as a finction EventName(). So calling an event means actually going to all the methods that were registered to that event and doing them.
But, this is done in the same thread in a serial way.
So if an event happened in a thread that is not your UI thread you'll get theat error.
The issue is that the GUI components only accepts modifications from the GUI thread. So when other threads want to modify the GUI, then they must queue their modification code using measures like control.Invoke(...) which will queue the delegate to be processed as soon as possible on the GUI event queue, and thus the correct thread.
What you run in to is that one of the built-in checks are fired than controls that the calling thread indeed is the correct thread. It is a security measure that makes debugging easier (if they were not present you would have to debug subtle threading issues instead...)
textBox1.Text = "test" doesn't work because you are calling it from another thread (i.e. the DataHasBeenReceived event) then the thread who owns the textbox. That's usually the thread in which your application runs and that creates your GUI interface (and thus your textbox). Invoke works because that methods switches to the GUI thread, sets your text and then switches back to the thread of your DataHasBeenReceived event.
In Net 1.0 and 1.1 you could use GUI controls from another thread then then the one that owned them but this resulted in a lot of problems when threads started accessing the controls at the same time. So, since net 2.0 Microsoft changed that.
If you want to know if must use invoke or not (i.e. if a method can be called from the both the GUI thread or another thread), you can use the property InvokeRequired combined with an if else. A invoke call is slightly more expensive then a direct manipulation of the control.
Whilst debugging my program in VS 2008 I have come across the following error:
The CLR has been unable to transition from COM context 0x34fc1a0 to COM context 0x34fc258 for 60 seconds. The thread that owns the destination context/apartment is most likely either doing a non pumping wait or processing a very long running operation without pumping Windows messages. This situation generally has a negative performance impact and may even lead to the application becoming non responsive or memory usage accumulating continually over time. To avoid this
It appears to be deadlocking even though the code only contains a simple C# timer: See Snippet Below:
private void RequestWork()
{
// The timer will be re-intialised if there are still no wating jobs in the database
StopTimer();
// assign all the threads some work
InitialiseTimer();
}
/// <summary>
/// Initialise a timer with a timer interval configured from app.config. Enable the timer and
/// register an appropriate event handler
/// </summary>
private void InitialiseTimer()
{
if (m_Timer == null)
{
// look up the default backoff time from the config
string backOffInt = ConfigurationSettings.AppSettings["BackOffInterval"];
int backoffInterval = 1000;
m_Timer = new System.Timers.Timer();
// set the timer interval to 5 seconds
m_Timer.Interval = backoffInterval;
m_Timer.Elapsed += new ElapsedEventHandler(m_Timer_Elapsed);
}
m_Timer.Enabled = true;
}
private void StopTimer()
{
if (m_Timer != null)
{
m_Timer.Enabled = false;
}
}
void m_Timer_Elapsed(object p_Sender, ElapsedEventArgs p_E)
{
RequestWork();
}
As far as I know the timer should run, elapse and then initialise again, I can see no local reason for a deadlock.
I am aware of how to turn this error msg off but feel that this is not a solution, instead it is masking the problem.
You can turn this off if you think you've definitely not got a deadlock situation:
Debug->Exceptions->Managed Debug Assistants menu in Visual Studio and uncheck the ContextSwitchDeadlock
This is an infinite loop. You need to let your application pump some messages at least once every 60 seconds to prevent this exception to happen.
Try calling System.Threading.Thread.CurrentThread.Join(10) once in a while. There are other calls you can do that let the messages pump.
It seems that you are adding a new event handler each time you call InitialiseTimer. That way m_Timer_Elapsed will be called as many times as it has been added.
You should add the event handler just one time.
If your application hangs or not reponse even after you uncheck the box against contextswitchdeadlock. Put the following line before call of method or for loop.
In C#
System.Windows.Forms.Application.DoEvents();
and VB.NET / VB / ASP.NET
DoEvents()
Couple thoughts/questions:
1) The code snippet looks like your interval is every 1 second (not 5 as mentioned in the comments).
2) The big question is what is RequestWork() doing?
Without knowing what RequestWork() is doing, we can't really comment on why you are seeing a ContextSwitchDeadlock.
Somethings to think about with respect to this method
a) how long does it take?
b) is it accessing GUI elements?
Some MSDN comments on Elapsed:
If you use the Timer with a user
interface element, such as a form or
control, assign the form or control
that contains the Timer to the
SynchronizingObject property, so that
the event is marshaled to the user
interface thread.
-and-
The Elapsed event is raised on a
ThreadPool thread. If processing of
the Elapsed event lasts longer than
Interval, the event might be raised
again on another ThreadPool thread.
Thus, the event handler should be
reentrant.
I'm thinking since you have a 1 second timer, you might want to look into what happens in RequestWork and see how long its taking.