|
Hi Dave,
I have simplified your code and added lots of observation code; it still behaves basically as before.
here are preliminary ideas/observations (with insufficient proof):
1. when instantiating a class with a destructor, the object is added to the finalizer queue right away;
2. when the app exits, the destructor of all objects in the finalizer queue is (probably?) executed;
3. 1+2 explains how your CloseAll gets executed at all; it does not need a GC pass, no mark-and-sweep or whatever they use to locate dead objects: at the app exit, everything is considered dead, so simply finalizing everything still in the finalizer queue makes sense (an object finalized earlier would have been removed from the list already).
4. on app exit the objects, in particular the ports, are not collected (wouldn't make any sense as all memory is about to get freed anyway).
5. the order in the finalizer queue might be simply chronological, hence your Manager instance comes before your Port instances. And as long as your Manager hasn't been collected, neither have your ports, as your Manager is keeping a list of ports.
6. I'm with Gideon[^] when he says your destructor isn't in the right place; a destructor/finalizer/dispose should not rely on any other object, so giving each Port its own destructor would solve that, and make the above #5 irrelevant.
This article[^] looks very relevant and interesting; I haven't read it completely yet.
I may write a little article on the subject. I'll be back with more.
Luc Pattyn
I only read code that is properly indented, and rendered in a non-proportional font; hint: use PRE tags in forum messages
|
|
|
|
|
All very interesting points Luc which make a lot of sense when explaining the observed behaviour.
Re point 6. Normally I would agree with you, however... having a Dispose method would imply that a port couldn't/shouldn't be reused after disposal. All ports need to be reusable from anywhere (hence the Manager class to retrieve the same instance from at any time) until they are definately finished with i.e. at application exit, therefore I feel that having a 'Dispose' method would be confusing and counter intuitive to the consumer of the library as i don't actually want to dispose of anything and nothing is being actually disposed. I just want the ports to be correctly closed. To this end I have provided a Close method for each port, and a helper CloseAll in the port Manager.
Any comments on this (and anything) will be most welcome.
I'm about to study that article right now
Dave
"My code works, but I don't understand why!" - DaveyM69 (Me) BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Hi Dave,
I'm not saying your Port should implement IDisposable.
What I (and Gideon) mean is you should provide a finalizer for Port, so it can close itself; destructors/finalizers/disposers are not allowed to rely on other objects, so a Manager closing all Ports upon finalization is against the rules. So it seems:
- Ports should finalize themselves;
- the Manager may be redundant (happens often), or just provides a CloseAll but no finalizer calling it.
I haven't tested this yet.
BTW: The way I understood it Joe's article tries to make clear finalizers aren't 100% trustworthly. For one, a process kill (e.g. thru Task Manager) will not close the ports, whatever code you provide.
Luc Pattyn
I only read code that is properly indented, and rendered in a non-proportional font; hint: use PRE tags in forum messages
|
|
|
|
|
Closing itself can be problematic (see post below) I believe due to the callback that happens from the MIDI driver back to the port instance once closure has finshed so post the Close method. The static use of the ports seems to keep them alive for at least long enough for the callback (untested so far). I have previously attempted a static delegate with no improvement. Also, there is no gurantee when the Port's finalizer will be called so the auto close may not happen when it needs to.
(All this is just a safety net against stupidity to cope with the possible case that a consumer doesn't explicitly call Close on any open ports or Manager.CloseAll.)
Luc Pattyn wrote: finalizers aren't 100% trustworthly ... Task Manager
I don't believe, using managed code at least, that there is anything I can do to deal with that situation so I have no choice but to live with it.
That was a great link by the way - thanks! Bookmarked for rereading several times until it all sinks in and for future reference.
Dave
"My code works, but I don't understand why!" - DaveyM69 (Me) BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
 After sleeping on it, I'm pretty sure that the callback is the source of the issues that prevent me from using the finalizer (either with or without Dispose) to close the port. It's clearer to see in code! Is there any reliable way to prolong the life of a delegate instance?
using System;
using System.Runtime.InteropServices;
public class Output
{
private const int CALLBACK_FUNCTION = 0x00030000;
private const int MOM_CLOSE = 0x3C8;
private const int MOM_OPEN = 0x3C7;
private delegate void MidiProc(
IntPtr hMidi,
int wMsg,
int dwInstance,
int dwParam1,
int dwParam2);
[DllImport("winmm.dll")]
private static extern int midiOutClose(
IntPtr hmo
);
[DllImport("winmm.dll")]
private static extern int midiOutOpen(
out IntPtr lphmo,
int uDeviceID,
MidiProc dwCallback,
int dwCallbackInstance,
int dwFlags
);
private MidiProc callback;
private IntPtr handle;
private int id;
public Output(int id)
{
callback = OnCallback;
handle = IntPtr.Zero;
this.id = id;
}
~Output()
{
Close();
}
public void Close()
{
if (handle != IntPtr.Zero)
{
midiOutClose(handle);
handle = IntPtr.Zero;
}
}
private void OnCallback(
IntPtr hMidi, int wMsg, int dwInstance, int dwParam1, int dwParam2)
{
}
public void Open()
{
if (handle == IntPtr.Zero)
midiOutOpen(
out handle, id, callback, id, CALLBACK_FUNCTION);
}
}
Dave
"My code works, but I don't understand why!" - DaveyM69 (Me) BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Further to my earlier reply, if I were to implement IDisposable the Port class would need to look something like this. I think this is messier but I do understand the reasoning for the recommendation for using Dispose .
using System;
namespace MIDI.NET.Ports
{
public abstract class Port : IDisposable
{
bool disposed;
~Port()
{
Dispose(false);
}
public virtual void Close()
{
if (disposed)
throw new ObjectDisposedException(
ToString(),
"This port has been disposed. If you wish to reuse it please use the ReCreate method.");
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
}
Close();
disposed = true;
}
}
public void Recreate()
{
if (disposed)
{
GC.ReRegisterForFinalize(this);
disposed = false;
}
}
}
}
I haven't tested this yet, but I'm 99% certain this gave me problems when I tried a similar implementation some months ago. Sometimes ports never closed so the application hung (often invisibly) or it created system instability, sometimes I got Access Violation (or similar) errors. I never got to the bottom of the problem but I figured it was one of the following:
1. Close being called on the instance could not be guaranteed to be successful as fields of the class may no longer be accessible (a loose theory and quite possibly/likely wrong!)
2. When calling Open on the port a callback is created which lasts beyond the call to Close as the Close itself generates a callback. Once this callback is registered it cannot be unregistered (that's the way the API works). Calling Close during Dispose may be too late as the callback delegate (and it's target) may now be collected making the unmanaged callback invalid (quite probable although badly explained!)
Dave
"My code works, but I don't understand why!" - DaveyM69 (Me) BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Dear all,
Could anyone please help me with the following problem. I have a MainForm in my application. I call a background worker thread to do some work. This thread never finishes, so it will always run in the background and will be closed when the application closes. This works perfect. Then I open a new form from my main thread and in that form I call another backgroundworker. As long as backgroundworker 2 is running, backgroundworker 1 becomes unresponsive. The MainForm stays responsive, the newly opened form stays responsive, but the two backgroundworkers don't seem to like each other and seems to be competing over resources.
* MainForm - backgroundworker 1
* subForm - backgroundworker 2
When backgroundworker 2 is running, backgroundworker 1 becomes unresponsive until backgroundworker 2 is finished.
Weird huh ?
Kind regards,
|
|
|
|
|
Rick van Woudenberg wrote: Weird huh ?
No. It's called a race condition and is a common problem when novices try multi-threaded programming
What are these threads doing? Are they trying to utilize the same resources?
http://msdn.microsoft.com/en-us/library/1c9txz50.aspx[^]
only two letters away from being an asset
|
|
|
|
|
in form1 i got
menu : File option help
open fix
form2 fix
how can i access fix design window from form1-> menu-> fix. you know, you press and choice fix from option menu in form1 and form2 fix will be opened
thx. 
|
|
|
|
|
Read documentation from net on Menu control first, you come to know how to do it.
|
|
|
|
|
Double click on the menu button in your designer. This will create an EventHandler.
Inside the EventHandler, put the following code :
private void OpenFix_Click(object sender, System.EventArgs e)
{
Form2 fix = new Form2();
fix.Open();
}
|
|
|
|
|
please provide any sample code
|
|
|
|
|
Parent Form :
public ProgressBar pb;
private void openChild_Click(object sender, System.EventArgs e)
{
ChildForm cf = new ChildForm();
cf.pf = this;
cf.open();
}
Child Form :
public ParentForm pf;
private void runProgressBar_Click(object sender, System.EventArgs e)
{
for(int i = 0;i<100;i++)
{
pf.pb.Value++;
}
}
|
|
|
|
|
Ick, I hope that was intentionally ironic!
|
|
|
|
|
i want to update progressbar in Child form not in Parent form
|
|
|
|
|
Simplest method is to add events to your child form that the parent subscribes to when the form is created. You can then use these to notify the parent that the progress needs changing.
Any sample code? Here's Hello World as a Vax-11 macro[^]
|
|
|
|
|
Hi everyone!
I have got a problem with Chinese fonts displayed on Crystal Report pdf.
I have these fonts installed on the server system(East Asian language pack enabled) and I change the *.rpt file font in runtime, using Ms Song font...but when I generate pdf this font is not displaying(Sans serif have appeared instead of MS Song ) but the font of *.rpt has been changed to Ms Song I have checked it.
Did anyone have such problems?
I'll be very appreciated for any help!
|
|
|
|
|
Why cant i do this? The value of "args" will be of similar format to the value i assigned to it. Im getting a "Index was outside the bounds of the array" error
static void Main(string[] args)
{
args[0] = "FrGbWOfvwO0=";
}
|
|
|
|
|
I guess the args is not initialized with any length of you don't start your application with any arguments. Why do you want to add values to the args array inside your code anyway?
|
|
|
|
|
Because it would be pointless ? The args collection is passed in, and exists only inside this method, why would you have any desire to change it ?
Christian Graus
Driven to the arms of OSX by Vista.
Read my blog to find out how I've worked around bugs in Microsoft tools and frameworks.
|
|
|
|
|
There is no element in the array args if you don't run the program with a command-line parameter. Therefore, args[0] does not exist. 0 is out of range.
|
|
|
|
|
In a recursive function for traversing a tree nodes , I want to invoke a function for the last child of a parent node( including all its grandchilds ). I have not found a technique for finding that node in the recursive function .
Any help ?
Thanks in advance.
|
|
|
|
|
List<TreeNode> nodeList = new List<TreeNode>();
private List<TreeNode> GetChildNodes(TreeNode treeNode)
{
foreach (TreeNode oNode in treeNode.Nodes)
{
nodeList.Add(oNode);
if (oNode.Nodes.Count > 0)
{
GetChildNodes(oNode);
}
else {
// this is the last node
}
}
return nodeList;
}
This would give you list of nodes in order as they would appear in expanded tree view.
It's not necessary to be so stupid, either, but people manage it. - Christian Graus, 2009 AD
modified on Friday, October 23, 2009 6:39 AM
|
|
|
|
|
How to find the last grandchild of a parent node. All nodes have just one last grandchild.
in the following example node "node1_child3_child3" is the last grandchild of node1. Then how can I recognize that node in the recursive function ? What technique can I use ?
----node1
node1_child1
node1_child2
node1_child2_child1
node1_child2_child2
node1_child3
node1_child3_child1
node1_child3_child2
node1_child3_child3
modified on Friday, October 23, 2009 6:53 AM
|
|
|
|
|
If you need just the last node, change the return type of the method to treenode and use following code:
nodeList.Add(treeNode);
if (treeNode.Nodes.Count > 0) {
treeNode = GetChildNodes(treeNode.Nodes[treeNode.Nodes.Count - 1]);
}
return treeNode;
If you need complete heirarchy, you the following:
nodeList.Add(treeNode);
if (treeNode.Nodes.Count > 0) {
GetChildNodes(treeNode.Nodes[treeNode.Nodes.Count - 1]);
}
return nodeList;
It's not necessary to be so stupid, either, but people manage it. - Christian Graus, 2009 AD
|
|
|
|