|
In fact, it doesn't make a difference. Common misunderstanding. Let me first put in the code snippet
public void SetProgressValue(int value)
{
if( formClosed == true )
{
return;
}
if (this.InvokeRequired)
{
ProgressValueDelegate pvd = new ProgressValueDelegate(SetProgressValue);
this.Invoke(pvd, new object[] { value });
}
else
{
m_progressBar.Value = value;
}
}
When SetProgressValue is called from another thread, the first thing that happens is the check if the form is closed already. Let's take you hypothetical situation where a FormClosing event is queued, but has not been executed yet. formClosed is false , so now this.InvokeRequired is checked. It's true so a call to SetProgressValue is queued as well.
The FormClosing event fires, and formClosed is set to true. Next, the queued call to SetProgressValue occurs. First thing, we check formClosed which is now true , so the function is terminated immediately.
The common misconception is that Invoke simply transfers the call to the correct thread, but in fact the function is called all over again.
Another thing many people are not aware of is that the call to Invoke actually halts the thread until the Invoked delegate has been executed in the GUI thread, which can cause major slowdowns. Rather use BeginInvoke . It does the same thing in this scenario, but does not block the calling thread.
|
|
|
|
|
My mistake. You're right about the test, if it sits on the top of the method, it gets executed twice so it can't go wrong. However executing it twice all the time may be a high price to pay for potentially saving one thread switch when the form closes.
I do not really agree on the BeginInvoke issue. While technically correct, I don't like the SetProgressValue method to behave synchronously when called on the main thread and asynchronously when called anywhere else. If there is a potential asynchronous operation, it should be reflected in the method name (BeginSetProgressValue?) and it'd better be consistent (as in: don't test InvokeRequired, just call BeginInvoke). Furthermore, having a mix of such Invoke and BeginInvoke patterns (several Controls each using their own little SetProgressValue method) could result in incomprehensible app behavior.
|
|
|
|
|
Luc Pattyn wrote: My mistake. You're right about the test, if it sits on the top of the method, it gets executed twice so it can't go wrong. However executing it twice all the time may be a high price to pay for potentially saving one thread switch when the form closes.
Hey, no problem. I make mistakes all the time. Hence my motto There are two ways to write bug free software. Only the third method works though
As for the performance cost argument, I think it's highly dependent on the scenario.
Luc Pattyn wrote: I do not really agree on the BeginInvoke issue.
I agree with you. In a large project or any other production level code, things should be done consistently, and all the things you mention are true. That is why I stated that in this simplified scenario, BeginInvoke doesn't really matter. If the function was even remotely more complex, or had more than 3 lines to execute with the synchronous vs. asynchronous path, it would be far more important.
Glad we could agree
|
|
|
|
|
I'm not sure how to satisfy Luc's issue over mixing sync and async behaviours, but how about this variation:
public void SetProgressValue(int value)
{
MethodInvoker method = delegate
{
if (!formClosed)
{
m_progressBar.Value = value;
}
};
if (InvokeRequired)
BeginInvoke(method);
else
method.Invoke();
}
First, you don't need to worry about keeping the delegate's parameters aligned with the method's parameters (makes maintenance easier). Second, you shouldn't test boolean values against true/false (just take their value). Third, it uses the async BeginInvoke when not on the GUI thread.
|
|
|
|
|
I like it, especially if you scrap the "Begin" of BeginInvoke.
|
|
|
|
|
It seems that, for some reason, your dialog is beeing disposed (and with it, all it's controls). It's really difficult to know why without more code.
But have you tried handling FormClosing event? There you could do this:
e.Cancel = true;
this.Hide();
Maybe that will work out for you, hiding instead of closing. Let me know if it solves your problem
Regards,
Fábio
|
|
|
|
|
Hi there,
I would love to get my hands on your code and experiment. I am way too lazy to write a new one. If you think you can write a small app that simulates your prob or share your code itself, please do so.
I would love to solve the riddle. =]
|
|
|
|
|
Just a thought - Have you checked to see if the thread is still alive? It may be that the closing form is triggering the thread itself to close or change states, preventing the continued use without restarting it.
Jack of all trades ~ Master of none.
|
|
|
|
|
|
When developing apps that use worker threads which like to report back a status, a good technique I have used on projects is to set up a data structure (class or struct) that holds member variables for all the "stats" that the threads must update. Each thread updates the fields in the class/struct, without caring who may be "listening". For dialogs that like to report the status of these threads (i.e. using progress bars, updating text boxes etc), they query the class / struct member variables. This way the relationship is decoupled and state-free.
This is a technique we used a lot in the Win32 programming model, and it works just as well in .Net.
|
|
|
|
|
Hi.
I am looking for the best solution to my problem. In short, I need to make a form that looks like an existing piece of paper. This paper is a formular, which you would normally fill out by hand. Instead, this form contains textfields, checkboxes and so on.
The important thing is, that this form shall NOT look like a form, but should look like the paper formular. That means the possibility of background elements, customized textboxes without the white background and black borders, and so on.
How do you achieve this goal in the easies way? Some kind of special technology you could use?
Thanks alot for your time
Kind regards,
Lars
|
|
|
|
|
If it's a desktop application I'd use WPF. A good designer can restyle the standard elements however you like.
|
|
|
|
|
Thanks alot, I will take a look at WPF
|
|
|
|
|
You are welcome.
|
|
|
|
|
|
Hi all,
In our application, we need to call functions from external assembly. Below is what we have already done?
1 Please note that user can create his own assemblies and can call any static public functions in those assemblies from our application.
2 Once the user has created his assembly, he let our application know which function in that assembly is to be called.
3 We load user specified assembly in a separate application domain.
4 We determine if the function that user wants to execute, actually exists in that assembly. (For this we use reflection to get complete information of the assembly).
5 Then we create parameters that are to be passed to the function in external assembly. For preparing parameters we are using a class Arg derived from interface MarshalByRefObject as below:
internal abstract class Arg : MarshalByRefObject
{
...
}
So Arg's object will represent parameters to be passed.
6 Now the problem comes. More the parameter we pass to a function in external assembly, more the memory leaks are there. If we call a function several times, memory leaks grows proportionally (even when that separate app-domain is unloaded).
7 So the reason of these memory leaks is that parameters (represented by Arg class derived from MarshalByRefObject) are not being collected by Garbage Collector (even when called explicitly).
8 Any comment on how can we free objects of Arg (created for passing parameters)? Or is there something that we should take extreme care about while doing stuff like this?
Regards
Aseem
|
|
|
|
|
when objects are no longer required yet fail to get collected, the most common cause is you still are referencing them somehow. Maybe you have a collection of Arg instances somewhere, which is growing all the time? A simple Clear() could fix that. Remember, a static class is loaded and initialized on its first use and never relinquished.
|
|
|
|
|
The objects that we are creating are purely local to a function. And we don't have even a single global/static variable. So the reason is something else. I guess it has something to do with either Application-Domain or MarshalByRefObject. Something we should take care about them which we are not doing.
|
|
|
|
|
People may need to see the relevant code, in order to help you out.
|
|
|
|
|
I am sorry, I am not authorized to share the code. Also I cannot produce similar sample of code. Its too big and complex to understand. And I myself have just 1 month of experience in .Net.
This problem is very specific. Someone if know the things to be taken care about Application-Domain and MarshalByRefObject while calling functions from external assembly?
As objects derived from MarshalByRefObject are not getting collected by Garbage Collector, there could be some special way of freeing them from memory.
|
|
|
|
|
Have a read of this[^] article and pay particular attention to the lease management.
|
|
|
|
|
Seems I was unaware of the potential problems with MarshalByRefObject.
Here[^] is another article you may want to read.
|
|
|
|
|
I would see stuff like this when I was using mixed (managed C++) code. What I found was that the references to the called DLLs were not being released unless I unloaded them by hand.
So, what you might try is loading the DLLs dynamically in your C# app, then unloading them and setting their references to null when finished using them. Each time a DLL function is called, you might then reload the DLL, but this might help you get rid of your memory leak.
|
|
|
|
|
Once an assembly (a .Net dll) is loaded, it cannot be unloaded and so it will remain in application's address space until process's life time. To avoid this we should load an assembly in a separate application domain. An application domain can be unloaded whenever we want and while it unloads, it also unload all assemblies loaded inside it. So problem can not be resolved as you said. But yes, as you said we have mixed code of Unmanaged C++, Managed C++ and C#. Could this mix of code have any implication?
|
|
|
|
|
To be 100% sure what the problem is, crack out windbg with the SOS extension for .Net. You can use ADPlus to take a memory dump of the .Net process in question, and then load the dump file into windbg.
The SOS debugger extension is used for debugging .Net memory dumps. Using !dumpheap -stat will show you all instances of objects on the heap. Given an instance handle, using !gcroot <handle> will tell you which thread is keeping the instance alive. Using !clrstack for that thread will show you the stack for that thread, pin pointing the exact code.
These commands are only the tip of the iceberg though, check out Tess Fernandez's blog at http://blogs.msdn.com/b/tess/[^] for help on using windbg for memory leak debugging in .Net.
|
|
|
|