|
Luc Pattyn wrote: When using the InvokeRequired/Invoke pattern, I hesitate to use Control.BeginInvoke() as that modifies the semantics of the method: when on the right thread, it works synchronously, whereas on another thread it only executes asynchronously. I am aware the thread switches are expensive though.
No. If you don't check InvokeRequired but simply use BeginInvoke every time, it will always be asynchronously. If the code is already running on the GUI thread, the delegate won't be executed immediately but enqueued in the message loop.
Using BeginInvoke on the GUI thread is a way to say "call this later", similar to "call this on next Idle event" (but I think it has much higher priority than Idle).
I don't know where the recommendation to check InvokeRequired came from, but everyone seems to copy it whenever writing about Invoke/BeginInvoke. I never use InvokeRequired that way; I use it only in the form Debug.Assert(!InvokeRequired); .
- Checking InvokeRequired when calling Invoke is useless (Invoke already does that).
- Checking it when calling BeginInvoke is dangerous as it changes semantics (makes asynchronous call synchronous).
Add to that that InvokeRequired can produce false negatives (if the control handle hasn't been created yet), and checking InvokeRequired is highly dangerous for anything but safety checks.
|
|
|
|
|
Very interesting approach.
Let me make clear what I am doing. I am trying to build an ANN (neural net).
1. TextBox is used for displaying information in real time, i.e. the number of training pairs, the starting time, end time, etc. This is just for me to keep track, plus it looks cool
2. A class with all the GUI controls and a class with the main training method. A delegate and event in the training class serve as the synch update of the information (also for number 1). e.g.
trainingANN_instance_LogReportSynch
3. I am not very familiar with threads, I've tired to use the approach with InvokeRequired , but I cannot understand why my events do not work. As an example:
private void butTraining_MouseClick(object sender, MouseEventArgs e)
{
this.trainingANN_thread = new Thread(new ThreadStart(this.Initiate_ANN_Training));
LockOptions();
this.tbVeryBig.Clear();
this.trainingANN_thread.Start();
this.tbVeryBig.Text += "[" + DateTime.Now.TimeOfDay.ToString() + "]: INITIALIZATION\r\n";
}
private void SettingsInfoDisplay()
{
if (this.InvokeRequired)
{
DelegateToCrossThread_None crossThreader = new DelegateToCrossThread_None(SettingsInfoDisplay);
this.Invoke(crossThreader);
}
else
{
this.tboxOutputNeuron.Text = "" + outputNeurons;
this.tboxInputNeuron.Text = "" + inputNeurons;
this.tboxHiddenNeuron.Text = "" + tbarHiddenN.Value;
this.tboxErrorTreshold.Text = "" + (this.tbarErrorTreshold.Value / 100.0);
this.tboxTrainingRate.Text = "" + (this.tbarTrainingRate.Value / 100.0);
this.tbBadF.Text = "<not defined>";
this.tbAccuracy.Text = "<not defined>";
this.tbConvergeRate.Text = "<not defined>";
this.tbErrorCounter.Text = "<not defined>";
this.tbRatio.Text = "<not defined>";
this.tbGoodF.Text = "<not defined>";
this.tbEpoch.Text = "<not defined>";
}
}
private void Options()
{
if (this.InvokeRequired)
{
DelegateToCrossThread_None crossThreader = new DelegateToCrossThread_None(Options);
this.Invoke(crossThreader);
}
else
{
errorTreshold = (double)((tbarErrorTreshold.Value) / 100.0);
learningRate = (double)((tbarTrainingRate.Value) / 100.0);
hiddenNeurons = tbarHiddenN.Value;
if (this.cboxLog.Checked != true)
{
logOption = false;
}
else
logOption = true;
}
}
private void Initiate_ANN_Training()
{
if (this.InvokeRequired)
{
DelegateToCrossThread_None crossThreader = new DelegateToCrossThread_None(Initiate_ANN_Training);
this.Invoke(crossThreader);
}
else
{
SettingsInfoDisplay();
Options();
this.tbVeryBig.AppendText("text");
trainingANN_instance = new ANN_Training();
this.tbVeryBig.Text += "[" + DateTime.Now.TimeOfDay.ToString() + "]: ANN TRAINING STARTED!\r\n";
trainingANN_instance.GoodFactsSynch += new StatsSynch(trainingANN_instance_GoodFactsSynch);
trainingANN_instance.BadFactsSynch += new StatsSynch(trainingANN_instance_BadFactsSynch);
trainingANN_instance.RatioSynch += new StatsSynch(trainingANN_instance_RatioSynch);
trainingANN_instance.ConvergeRateSynch += new StatsSynch(trainingANN_instance_ConvergeRateSynch);
trainingANN_instance.EpochSynch += new StatsSynch(trainingANN_instance_EpochSynch);
trainingANN_instance.LogReportSynch += new StringSynch(trainingANN_instance_LogReportSynch);
trainingANN_instance.BadFactsForGraphSynch += new StatsSynch(trainingANN_instance_BadFactsForGraphSynch);
trainingANN_instance.Training(inputNeurons, hiddenNeurons, outputNeurons, errorTreshold, learningRate, progressFilter, logOption);
this.tbVeryBig.Text += "[" + DateTime.Now.TimeOfDay.ToString() + "]: ANN TRAINING FINISHED!\r\n";
double ratio = (trainingANN_instance.good / trainingANN_instance.bad * 100);
this.tbRatio.Text = (Math.Round(ratio, 5)) + "%";
this.tbEpoch.Text = trainingANN_instance.epoch.ToString();
this.tbBadF.Text = trainingANN_instance.bad.ToString();
this.tbGoodF.Text = trainingANN_instance.good.ToString();
this.tbConvergeRate.Text = Math.Round((trainingANN_instance.progressRatio_temp), 5).ToString() + "%";
this.tbVeryBig.Text += "[" + DateTime.Now.TimeOfDay.ToString() + "]: RESULTS:\r\n EPOCH: " + trainingANN_instance.epoch.ToString();
this.tbVeryBig.Text += "\r\n BAD FACTS: " + trainingANN_instance.bad.ToString();
this.tbVeryBig.Text += "\r\n GOOD FACTS: " + trainingANN_instance.good.ToString();
this.tbVeryBig.Text += "\r\n RATIO: " + ratio + "\r\n CONVERGE RATE: " + Math.Round((trainingANN_instance.progressRatio_temp), 5).ToString() + "%";
UnlockOptions();
trainingANN_thread.Abort();
}
}
private void trainingANN_instance_RatioSynch(double variable)
{
if (this.InvokeRequired)
{
DelegateToCrossThread_Double del = new DelegateToCrossThread_Double(trainingANN_instance_RatioSynch);
this.Invoke(del);
}
else
{
this.tbRatio.Text = "" + variable;
}
}
So as you can see i commented App.DoEvents(). Without that line, events do not work, using my approach.
Another observation. When logOption was false or no DoEvents() in the code present, and textbox used to be updated with the += approach, the application used to freeze for certain seconds and only show the output after the training method of class 2 was done, however, if i try to display that info using Console.Write(), it worked fine. However, now, with new ideas with AppendText() , it works without problems.
modified 1-Aug-19 21:02pm.
|
|
|
|
|
All your calculations are still running on the main thread.
You start a new thread for Initiate_ANN_Training , but that method than immediately invokes back to the main thread. You're running all calculations on the GUI thread, just as if you did not create a new thread in the first place.
You should call Invoke only for the operations that need access to the GUI (accessing text box controls), but not for your expensive calculation (I'm guessing that's the trainingANN_instance.Training call?)
|
|
|
|
|
Yes, you are right. So how would you recommend going about it? Any hints pls? Should I separate the training call?
modified 1-Aug-19 21:02pm.
|
|
|
|
|
Split Initiate_ANN_Training into 3 methods: initialization, training, displaying results.
Use Invoke only in those methods that need to access the GUI: initialization, displaying results, and the logging events.
|
|
|
|
|
Did you mean something like that
private void Initiate_ANN_Training()
{
SettingsInfoDisplay();
Options();
DisplayInformation();
trainingANN_instance = new ANN_Training();
ANN_Events();
StartTraining();
?
modified 1-Aug-19 21:02pm.
|
|
|
|
|
A TextBox is fine for logging output. It also allows the user to copy out text blocks (which isn't easily possible with a ListBox ).
Please see my reply to Luc on how to improve performance when logging to a TextBox.
You've made two mistakes that dramatically slow down your code (using += on strings and letting the background operation wait for the textbox).
|
|
|
|
|
Thanks a lot, very helpful. Can you explain a bit more about
Daniel Grunwald wrote: letting the background operation wait for the textbox). , please.
The first one (+= part) as far as I understood is better to implement via .Append(x).
Thanks a lot. Still learning Appreciate all your help, guys!
modified 1-Aug-19 21:02pm.
|
|
|
|
|
When you call Invoke(someDelegate); from a thread other than the GUI thread, it will send the message "please execute this delegate" to the GUI and wait until that message was processed.
That means your calculation thread is waiting for the GUI to repaint the TextBox after displaying the message!
Also, it is much faster to group several log messages and append them in a single AppendText call.
So my proposed solution was to let the background thread add log messages to a some kind of buffer (e.g. StringBuilder). A timer on the GUI thread then regularly moves the text from the buffer to the TextBox.
readonly object loggerLock = new object();
StringBuilder loggerBuffer = new StringBuilder();
private void trainingANN_instance_LogReportSynch(string stringname)
{
lock (loggerLock) {
loggerBuffer.Append(stringname);
}
}
void logTimer_Tick(object sender, EventArgs e)
{
string newText;
lock (loggerLock) {
newText = loggerBuffer.ToString();
loggerBuffer.Length = 0;
}
if (newText.Length > 0)
tbVeryBig.AppendText(newText);
}
|
|
|
|
|
Yes, with a System.Windows.Forms.Timer one can avoid all Invoke() calls, which is good.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that. All Toronto weekends should be extremely wet until we get it automated in regular forums, not just QA.
|
|
|
|
|
I am a bit confused. Can you explain it pls if u dont mind?
modified 1-Aug-19 21:02pm.
|
|
|
|
|
EARNEST_OLEK wrote: I am a bit confused. Can you explain it pls if u dont mind?
OK, I think i got the idea...thanks, i will try to re-implement my program, Thanks. I will post the updates
modified 1-Aug-19 21:02pm.
|
|
|
|
|
I've read certain articles several times. Implemented it as it says, but still can't fix the problem
modified 1-Aug-19 21:02pm.
|
|
|
|
|
I wrote an article here last week that addresses this:
Multithreading, Delegates, and Custom Events[^].45 ACP - because shooting twice is just silly ----- "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "The staggering layers of obscenity in your statement make it a work of art on so many levels." - J. Jystad, 2001
|
|
|
|
|
Hey, guys. I think i managed to sovle, but I've got few questions.
My solution:
private void Initiate_ANN_Training()
{
MethodInvoker guiUpdateDuringLearning = new MethodInvoker(ThreadDynamic);
MethodInvoker guiUpdateAfterLearning = new MethodInvoker(AfterLearning);
SettingsInfoDisplay();
Options();
trainingANN_instance = new ANN_Training();
Invoke(guiUpdateDuringLearning);
trainingANN_instance.GoodFactsSynch += new StatsSynch(trainingANN_instance_GoodFactsSynch);
trainingANN_instance.BadFactsSynch += new StatsSynch(trainingANN_instance_BadFactsSynch);
trainingANN_instance.RatioSynch += new StatsSynch(trainingANN_instance_RatioSynch);
trainingANN_instance.ConvergeRateSynch += new StatsSynch(trainingANN_instance_ConvergeRateSynch);
trainingANN_instance.EpochSynch += new StatsSynch(trainingANN_instance_EpochSynch);
trainingANN_instance.LogReportSynch += new StringSynch(trainingANN_instance_LogReportSynch);
trainingANN_instance.BadFactsForGraphSynch += new StatsSynch(trainingANN_instance_BadFactsForGraphSynch);
trainingANN_instance.Training(inputNeurons, hiddenNeurons, outputNeurons, errorTreshold, learningRate, progressFilter, logOption);
Invoke(guiUpdateAfterLearning);
}
For events methods:
private void trainingANN_instance_RatioSynch(double variable)
{
if (this.InvokeRequired)
{
BeginInvoke(new DelegateToCrossThread_Double(trainingANN_instance_RatioSynch), new object[] { variable });
return;
}
else
{
this.tbRatio.Text = "" + variable;
}
}
Question 1: BeginInvoke invokes asynch. What does it mean? If thread works on variable X and its current value 5, would it reflect value 5 or something else? My goal is to show real-time current information. Does BeginInvoke compromise this issue?
Question 2: What are other solutions to my "problem"? Would like to know alternative ways.
Question 3: At some point, if I leave my code as it was, except Initiate_ANN_Learning method, removing InvokeRequired from it, I get this error:
System.Reflection.TargetParameterCountException was unhandled
Message="Parameter count mismatch."
Source="System.Windows.Forms"
StackTrace:
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
at ANN_Project.ANN_GUI.trainingANN_instance_RatioSynch(Double variable) in C:\Users\EARNEST\Documents\Visual Studio 2008\Projects\ANN_take2\ANN_take2\ANN_GUI.cs:line 541
at ANN_Project.ANN_Training.Training(Int32 inputNeurons, Int32 hiddenNeurons, Int32 outputNeurons, Double errorThreshold, Double learning, Int32 optionSel, Boolean dynamicLogOption) in C:\Users\EARNEST\Documents\Visual Studio 2008\Projects\ANN_take2\ANN_take2\ANN_Training.cs:line 255
at ANN_Project.ANN_GUI.Initiate_ANN_Training() in C:\Users\EARNEST\Documents\Visual Studio 2008\Projects\ANN_take2\ANN_take2\ANN_GUI.cs:line 368
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
in my old
private void trainingANN_instance_RatioSynch(double variable)
{
if (this.InvokeRequired)
{
DelegateToCrossThread_Double del = new DelegateToCrossThread_Double(trainingANN_instance_BadFactsForGraphSynch);
this.Invoke(del);
}
else
{
this.tbRatio.Text = "" + variable;
}
}
Can some1 explain it pls?
Final question: Can some1 explain pls why MethodInvoke , BeginInvoke solved the problem, while InvokeRequired approach was useless?
Appreciate your input and understanding!
modified 1-Aug-19 21:02pm.
|
|
|
|
|
I have some performance issues. If I start moving when the calculation thread is activated, the textbox updates can freeze or hang up and then "jump" to new values, let's say it stopped updating on 23, then it will not respond for a second, and then will jump to 59 or so. Also, sometimes my application acts as if there is no multithreading there Does not respond
modified 1-Aug-19 21:02pm.
|
|
|
|
|
greetings, i am developing a battleships clone game and i have an issue with TableLayoutPanel MouseLeave event.
first MouseMove:
private PictureBox HomeLastPicBox = new PictureBox();
private TableLayoutPanelCellPosition homeLastPosition = new TableLayoutPanelCellPosition(0, 0);
private void HomeTableLayoutPanel_MouseMove(object sender, MouseEventArgs e)
{
PictureBox NowPicControl = (PictureBox)(HomeTableLayoutPanel.GetChildAtPoint(e.Location));
if ((NowPicControl != null) && (NowPicControl != HomeLastPicBox))
{
HomeLastPicBox = (PictureBox)(HomeTableLayoutPanel.GetControlFromPosition(homeLastPosition.Column, homeLastPosition.Row));
if (GameModel.HomeCellStatus(homeLastPosition.Column, homeLastPosition.Row) == Cell.cellState.WATER)
{
HomeLastPicBox.Image = Properties.Resources.water;
}
TableLayoutPanelCellPosition homeCurrentPosition = HomeTableLayoutPanel.GetCellPosition(NowPicControl);
if (GameModel.HomeCellStatus(homeCurrentPosition.Column, homeCurrentPosition.Row) == Cell.cellState.WATER)
{
NowPicControl.Image = Properties.Resources.scan;
}
homeLastPosition = homeCurrentPosition;
}
}
this appears to function properly.
now the MouseLeave event:
private void HomeTableLayoutPanel_MouseLeave(object sender, EventArgs e)
{
MessageBox.Show("col " + homeLastPosition.Column.ToString() + " row " + homeLastPosition.Row.ToString());
if (GameModel.HomeCellStatus(homeLastPosition.Column, homeLastPosition.Row) == Cell.cellState.WATER)
{
HomeLastPicBox.Image = Properties.Resources.water;
MessageBox.Show("hi");
}
HomeLastPicBox = new PictureBox();
}
this is acting strange. it goes through the code and even a "HI" is displayed but the PictureBox image is not changed to water. any ideas as to why? this does not happen all the time, only from time to time.
what the above code is doing is basically scanning through the table cells and if the cell content is WATER then it updates the table cell image to SCAN and as the user moves onwards it is switching the cell image back to WATER.
hope this is enough information. please ask if more is needed.
thank you in advance.
|
|
|
|
|
<pre>
if (GameModel.HomeCellStatus(homeLastPosition.Column, homeLastPosition.Row) == Cell.cellState.WATER)
{
HomeLastPicBox.Image = Properties.Resources.water;
MessageBox.Show("hi");
}
</pre>
i wonder why are you using this
<pre>HomeLastPicBox = new PictureBox();</pre>
when you have already assigned the picture to this picture box in the if block. after displaying the message box you need to return.
do it like this.
<pre>
if (GameModel.HomeCellStatus(homeLastPosition.Column, homeLastPosition.Row) == Cell.cellState.WATER)
{
HomeLastPicBox.Image = Properties.Resources.water;
MessageBox.Show("hi");
return;
}
hope it helps.
</pre>
Ahsan Ullah
Senior Software Engineer
MCTS 2.0
|
|
|
|
|
no thats not going to work. i have made some progress. the reason im experiencing this behaviour is because mousemove is being called after the call of mouseleave.
|
|
|
|
|
I have created a C# application that has 3 modules so far, default.aspx, registration.aspx and supplierinfo.aspx all using code_behind. I then created a class dbConnect.cs that I will use to connect to a DB. I am able to instatiate the dbConnect class in supplierinfo.aspx.cs and get the connection string. In the other 2 modules I am unable to instatiate the dbConnect class. I enter:
var dbCon = new dbConnect(); OR dbConnect dbCon = new dbConnect;
and then do a build. I am getting the following error:
Error 35 The type or namespace name 'dbConnect' could not be found (are you missing a using directive or an assembly reference?)
I can't see any differences in the modules that would cause this. Has anyone run into this before or have any suggestions what to look for?
Thanks for the help
|
|
|
|
|
So what you are saying is - all four classes belongs to the same namespace and you are still getting this error? Interesting.
I am thinking you may be missing a "using" statement.If you fail to plan, you plan to fail!
Books are as useful to a stupid person as a mirror is useful to a blind person. - Chanakya
|
|
|
|
|
Sometimes when we have a problem we fail to look at the obvious. We tend to look for the complex solution and not the simple solution. Turns out the problem is that 2 of the modules were not using the namespace.
Thanks for the help.
|
|
|
|
|
msg55121 wrote: Thanks for the help.
you are welcome If you fail to plan, you plan to fail!
Books are as useful to a stupid person as a mirror is useful to a blind person. - Chanakya
|
|
|
|
|
I have 256/DSL connection with non static IP and i have router to let me surf the net.
every time I connect to the internet I have Different IP.
is there a program to get this IP every time I connect.
|
|
|
|
|
Several options:
Stun / UPnP / Telenet acces to your box....
|
|
|
|
|