Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

.Net, Fred's webserver, and me


  • Please log in to reply
17 replies to this topic

#1 bill.french

bill.french

    Advanced Member

  • Members
  • PipPipPip
  • 260 posts
  • LocationPrinceton, NJ

Posted 27 October 2010 - 11:26 PM

Fred (and Others) Web Server

As someone who understands but tries to avoid ternary operators, because they scare when I try to read code, I think I am really close to understanding everything that is happening in the listener.cs file -- any suggestions on how to work through it? I need the "dummies" version before I can tackle the MSDN version that deal with the concepts. I feel like I need some help getting to the next level with .Net. I think my questions mostly deal with IDisposable and/or disposing of objects. Even suggesting a class from MS where this stuff can be learned would be appreciated.

My basic questions:
1. What is IDisposable all about? I see here that it's important to know about it
2. What's up with the ~Listener piece? Here's a fun discussion of the tilde. Reading that made me say: WUT JUST HAPPENED HERE?
3. I have heard before that using() (as in, using (ClientSocket)) does something special, like disposes of the object when it is done, is that true?
4. "#region IDisposable Members" -- what is up with the #region stuff?
5. Why are we dealing so explicitly with disposal of stuff at all? Is it for performance reasons? Or should we not trust things to get disposed of on their own?

Forgive me if these questions are dumb. I've been working with .net for years now, and basically avoiding these questions. The basic stuff I've done over the years works, and I can't figure out how or why to learn about this stuff -- but the smarter folks all seem to do it so it must be important, and not just stylistic choices. I've done some pretty cool things over the years but I'm guessing my code looks like it's written by a 4 year old. Thank you!

#2 phantomtypist

phantomtypist

    Advanced Member

  • Members
  • PipPipPip
  • 142 posts
  • LocationNew York, NY

Posted 28 October 2010 - 12:37 AM

Hi Bill,

I suggest you get a copy or eBook of Learning C# 3.0 by O'Reilly. Read that book first as it will give you a better understanding of C# and the .NET Framework in general.

If you understand the principles of object oriented programming already, then I'd say read Programming C# 4.0 by O'Reilly. It covers some of the stuff in the previous book I mentioned, but it goes over some more advanced concepts and stuff compared to the later.

Last, but not least, you should probably pick up a good book on design patterns. There is the C# 3.0 Design Patterns by O'Reilly which I have found useful.

Another great book is Code Complete Second Edition by Steve McConnell. If you are really passionate about programming you'll want to give that book a read.

I'd also like to mention of another book I started reading called C# in Depth by Jon Skeet. I'm really liking it. You may want to wait on this one as I've seen they are making a second edition that will be coming out soon.

#3 bill.french

bill.french

    Advanced Member

  • Members
  • PipPipPip
  • 260 posts
  • LocationPrinceton, NJ

Posted 28 October 2010 - 02:22 AM

I think my question is more technical than it might have come across. My oop is pretty good, i am weak on threading, and building disposers in the context of a GC is mysterious to me.

My understanding about why you might build your own disposers is when you're dealing with unmanaged code, or threading issues, or if you want to dispose of stuff in particular order for particular reasons -- otherwise the garbage collector takes care of its business pretty well.

So, in short, while I can read and understand the IDisposable interface, i'm struggling to understand why people use it in fully managed code situations outside netmf, and particularly with our nd+, what about the listener.cs code calls for the use of IDisposable?

#4 freds

freds

    Advanced Member

  • Members
  • PipPipPip
  • 61 posts

Posted 28 October 2010 - 02:34 AM

I think my question is more technical than it might have come across. My oop is pretty good, i am weak on threading, and building disposers in the context of a GC is mysterious to me.

My understanding about why you might build your own disposers is when you're dealing with unmanaged code, or threading issues, or if you want to dispose of stuff in particular order for particular reasons -- otherwise the garbage collector takes care of its business pretty well.

So, in short, while I can read and understand the IDisposable interface, i'm struggling to understand why people use it in fully managed code situations outside netmf, and particularly with our nd+, what about the listener.cs code calls for the use of IDisposable?


Well any project can become a memory hog, sort of the downfall to C# is that if you don't clean things up in deterministic manner you can get hit with difficult to diagnose bugs when the gargage collect does run later.

The best way to ensure an object that you are no longer using doesn't linger though GC is in the IDisposable method; unhook any events you have subscribed to (most common programmer mistake) and dispose of anything you allocated that has a IDisposable interface and null out references to external objects.

#5 phantomtypist

phantomtypist

    Advanced Member

  • Members
  • PipPipPip
  • 142 posts
  • LocationNew York, NY

Posted 28 October 2010 - 03:07 AM

Check out this Coding Horror blog article along the lines of garbage collection from Jeff Atwood.

And another from Jeff...

And another article from Tim Weaver discussing many of the things you want a better understanding about including the destructor ("~")...

#6 bill.french

bill.french

    Advanced Member

  • Members
  • PipPipPip
  • 260 posts
  • LocationPrinceton, NJ

Posted 28 October 2010 - 03:12 AM

This is like c# therapy.. thank you!

I like this explanation on using and IDisposable -- does that sound about right to you?

I've also figured out that the #Region stuff is not a requirement, just a nice way to structure the code, right?

Should you have "GC.SuppressFinalize(this);" as in here? Or is that not applicable in netmf?

Reading the webserver code, I am understanding how it's non-blocking -- but is it multithreaded? There's certainly threads involved, but to make it multithreaded, it seems that once you got a clientsocket, that should be spun off into it's own thread (which would deal with the response) so that the next connection could be accepted? I don't doubt that I'm misunderstanding this. Am I missing something?

Thank you so much for your time!

#7 phantomtypist

phantomtypist

    Advanced Member

  • Members
  • PipPipPip
  • 142 posts
  • LocationNew York, NY

Posted 28 October 2010 - 03:20 AM

I've also figured out that the #Region stuff is not a requirement, just a nice way to structure the code, right?


Some people have opinions about regions. Take a look at Jeff's blog post and read his four downsides to code folding.

#8 phantomtypist

phantomtypist

    Advanced Member

  • Members
  • PipPipPip
  • 142 posts
  • LocationNew York, NY

Posted 28 October 2010 - 03:24 AM

Should you have "GC.SuppressFinalize(this);" as in here? Or is that not applicable in netmf?


NETMF or regular .NET, you can use GC.SupressFinalize where appropriate. I used it in my Honeywell HIH-4030 Humidity Sensor managed driver.

#9 bill.french

bill.french

    Advanced Member

  • Members
  • PipPipPip
  • 260 posts
  • LocationPrinceton, NJ

Posted 28 October 2010 - 03:25 AM

Phantom, besides having some hilarious comments, your linked articles seem to argue against working so hard to explicitly dispose of objects c++ style, just when I was starting to get into it w/ c#. What I linked above seemed to argue for IDisposable in the context of exceptions and future-proofing, which I can get behind.

Most of what I've written in the past only dealt with exceptions as a bad thing that end a program, I do know that I need to explore using exceptions in positive ways, somewhat similar to events.

#10 bill.french

bill.french

    Advanced Member

  • Members
  • PipPipPip
  • 260 posts
  • LocationPrinceton, NJ

Posted 28 October 2010 - 03:29 AM

ourt post timing seems to be crossing... lol i appreciate your regions link, too. Concerning GC.SupressFinalize -- in your opinion would it be appropriate in the webserver? Why or why not?

#11 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 28 October 2010 - 03:37 AM

Hey Bill,

I'd like to take a stab at answering your questions. I'll start with #5. It will be easiest for me if I wax a little philosophical first. I'm sure much of this will be slow-going and repetitive for you, but this is the easiest way for me to get my thoughts out.

In .NET, Bill Gates has written a really nice garbage collection framework. You interact with this framework in an interesting and asymmetric way: when you want to allocate memory, you have to explicitly ask for it (via the "new" operator). However there is no way to explicitly say that you want to de-allocate memory. Instead, the system decides on its own when to reclaim memory. Exactly when the reclamation happens is based on a complicated algorithm, but in any case it is only allowed to happen at some point after the object becomes "unreachable". The definition of "unreachable" is also complicated, but the intuitive idea has to do with whether it can be reached, directly or indirectly, via some chain of references starting with all of the system's global and local variables. The reason this is "intuitive" is that if there is no way to get to an object, then there's literally no way of ever using it again, so "of course" the system can reclaim it.

In short, Bill Gates has given us a very nice system for managing our memory. But memory is only one kind of resource in a system. Our system also has other pools of limited, shared resources: I/O pins, file handles, network sockets, and so on. Wouldn't it be nice if Bill Gates had also written a generalized resource manager for us?

Unfortunately, he didn't. But if we use some tricks, we can take advantage of the garbage collection framework to get pretty far.

For the sake of example let's say that we are writing a library routine that aims to manage our Netduino's collection of I/O pins. In our library we would like to
  • Keep track of the pins in use
  • Provide a way for someone to allocate a pin (which fails if it's already in use)
  • Provide a way for the person to give back the pin

It turns out that it is fairly natural to do this with C# objects. The pattern is: when the object is constructed, that object's contructor method does the work of allocating the "real" underlying resource. So you might have this psuedocode:

public class OutputPort {
  private OS_SPECIFIC_RESOURCE_HANDLE handle; //whatever

  public OutputPort(Pins pin, bool initialState) {
    if(pin is in use)
      throw new Exception("sad");
    this.handle=...magic OS call to allocate the pin...
  }

Now we have a perfectly sensible solution to one-half of the problem. When a program wants an output port, they simple say "new OutputPort(whatever)" and store the result in a variable somewhere. Now the interesting part: what's the best way to provide the deallocation feature?

The first observation we would like to make is that it would be nice if our library did something "sensible" in the case where a program has "forgotten" about an OutputPort. By "forgotten" I mean that the object is no longer reachable, and by "sensible" I mean that the library can return the pin back to pool of free pins so that someone else can use it.

C# provides a mechanism for this via a specially-named method called a "finalizer". Bill Gates' approach with respect to finalizers is: at some point after an object becomes eligible for garbage collection, the system may turn its attention to that object. If that object has no finalizer method, its memory will simply be reclaimed. However, if it does have a finalizer method, the object will instead be added to a special queue. Then, at some further time, the system (running on a special "finalizer thread") will execute the finalizer methods of each of the objects belonging to this queue.

So now our code would look like this:

public class OutputPort {
  private OS_SPECIFIC_RESOURCE_HANDLE handle; //whatever

  public OutputPort(Pins pin, bool initialState) {
    if(pin is in use)
      throw new Exception("sad");
    this.handle=...magic OS call to allocate the pin...
  }

  ~OutputPort() {
    magic OS call to de-allocate the pin
  }

So this answers your #2 in part. The next question is, why isn't this good enough? Well I've been very careful to say that garbage collection doesn't happen at a definite time, only that it is eligible to happen when certain conditions hold. In particular, it might be a long time before the collector runs, or it might never run. So even if our hypothetical program doesn't have a reference to the OutputPort any more, the finalizer might not run for a long time.

So (answering your #1 in part) Bill Gates decided to create an interface called IDisposable, which has a single method called Dispose(). This establishes a convention for deallocating resources.

Now our sample library looks like this (note I am now implementing the interface IDisposable)

public class OutputPort : IDisposable {
  private OS_SPECIFIC_RESOURCE_HANDLE handle; //whatever

  public OutputPort(Pins pin, bool initialState) {
    if(pin is in use)
      throw new Exception("sad");
    this.handle=...magic OS call to allocate the pin...
  }

  ~OutputPort() {
    magic OS call to de-allocate the pin
  }

  void Dispose() {
    magic OS call to de-allocate the pin
  }


The caller might use it like this:

  var oport=new OutputPort(...);
  ...blah blah blah...
  oport.Dispose();

This is not really ideal, because what if "blah blah blah" throws an exception? Then Dispose() won't get called and our resource won't get freed (unless and until the finalizer runs, some arbitrary point in the future, or never)

Instead it would be a better defensive programming practice to write

var oport=new OutputPort(...);
try {
  ...blah blah blah...
} finally {
  oport.Dispose();
}

This is obviously better, as the finally clause will be executed regardless of whether we leave the "blah blah blah" part normally or via an exception. But seeing that this is a useful coding pattern, Bill Gates has provided a handy shortcut for the above. The code above is basically equivalent to the following much more concise utterance:

using(var oport=new OutputPort(...)) {
  ...blah blah blah...
}

That answers your #3. I'll just insert #4 right here and say that the #region...#endregion directives are just for code outlining... they are ignored by the compiler, but they allow Visual Studio to show/hide sections of code which have presumably been grouped by the programmer into logical regions and subregions. I don't really care for the #region directive and don't use it much.

Now to finish answering your #1. As you can see from our sample library, the Dispose() method and finalizer method do conceptually similar things and ought to share code. But you may be wondering why the link you posted has such complicated code. The answer is that Bill Gates is much smarter and richer than you and me, and therefore he has thought very hard about the difference between finalization and disposing. The rules are subtle and complicated (by the way, the link you posted also has it a little bit wrong) so I'll just say you should read Bill's rules, and I'll try to give just a few observations as to why the code is structured the way it is:

  • To avoid repeating code, the finalizer method and Dispose() both want to delegate their work to a helper method, passing either false or true so that the helper method knows which variant of the algorithm to execute
  • The helper method has a flag so that after the first dispose, subsequent calls to Dispose() or the finalize method do nothing
  • Unmanaged resources are unconditionally released in the helper method, whether called by Dipose() or the finalizer (i.e. whether the parameter passed was false or true). An example of an "unmanaged" resource is something we got from the underlying operating system, like say, some low-level file handler or a handle to an I/O pin.
  • Managed resources, on the other hand, should only be released in the "Dispose" context (when the incoming parameter is true). When called in the finalizer context (incoming parameter=false), you should do nothing. "Managed" resources means other C# objects, for example ones which also have a Dispose() method. The argument for why this rule is the way it is is a rather nitpicky one, in my opinion, which stems from the fact that when your finalizer has been called, you have no way of knowing the state of the C# objects you point to... for example it's possible that their finalizer has already been called as well. So you're basically a Bad Person for trying to call Dispose() on an object which has already been finalized. As I said it is a rather subtle argument, but it's for reasons like that that Bill Gates is one of the richest people in the world and I'm just sitting here drinking 5-Hour Energy Drink and posting to the Netduino forum.

Seriously, I think that covers all your 1-5. I hope you find it at least somewhat informative.

#12 Fred

Fred

    Advanced Member

  • Members
  • PipPipPip
  • 302 posts
  • LocationUK

Posted 28 October 2010 - 09:30 AM

Damn, I hate posting code online. You've gotta make sure you get it exactly right! I must admit I was wondering as I posted whether I should polish it up a bit.


IDisposable
Some great contributions above on the theory. Not much more I can add to this other than agreeing.

Hari's web server code had nothing but a comment that the socket was closed when you send a response. On a small device where all the code is written by you this could be sufficient, but I stuck IDisposable in to make sure that this expensive (and potentially port-blocking?) resource was freed up.

I would normally go with the full pattern (another good read here) but stuck it in quickly and simply and ensured the Dispose method was idempotent. (Be careful googling that or you may end up with even more emails offering you Viagra.)

Perhaps overkill going with the number of places I ensure that Dispose gets called. I'd be more than happy to see this improved upon.


Threading
Added a comment about this to my original post. The Listener is indeed a single thread and responds to a queue of requests synchronously on this thread. This is all my app need and I would guess is all most Netduino projects would need. We don't have the luxury of unlimited space and processing on the Netduino to add this if it isn't required.

If you need to respond asynchronously to multiple concurrent http requests then go ahead and extend the code. Spawning a new thread for the Request object should do it, I think. Then the main Listener thread can then head back to Accept() some more.

However, you may want to think about how much you're asking of this tiny device. Perhaps if each spawned request then becomes stuck waiting on an external event this would be useful. If your Netduino is actually doing some work it may be unresponsive anyway.

Finalizer
Probably not needed. Left in from Hari's original code.


Another point entirely
If you ever get asked the rather predictable interview question about the value/reference types and the heap/stack, this is a good read.

#13 bill.french

bill.french

    Advanced Member

  • Members
  • PipPipPip
  • 260 posts
  • LocationPrinceton, NJ

Posted 28 October 2010 - 12:20 PM

Damn, I hate posting code online.

Please please please don't stop!! Certainly not because of anything I've said! You're a hero in my book.

Wow, thanks everyone, I have read every word and I think I get it. My original post was primarily about tricking smart people into teaching me something I probably should have already known, for free. However, a part of me hopes I'm not alone and that it might be useful for someone else.

I also think this discussion really reveals how awesomely powerful the netmf is -- i can't imagine the competing platforms are having these types of discussions. I am certainly capable of understanding these things, but the subtleties of the implementation are tough, or at least, unobvious. (A tilde means what??)

I have been thinking about the using statement (and IDisposable, but not as much - and only tied the two together in the last 24 hours) for at least 5 years. I've read what it does, but have never gotten to the "but, why?" part. This line in the .net wiki sums up my frustration:

You should be familiar with the pattern or with the interface because it's a basic thing to know about the .Net framework.


Basic thing to know?? Why? I've read many books and created .Net applications that (admittedly small numbers of) people are actively using on a daily basis and never touched/actively avoided it.

I learn much better when there's a practical application involved, and the nd+ web server seemed like a perfect opportunity for me to bring myself forward with code I otherwise understand.

Concerning the multithreading, I agree that how it is done is probably the most appropriate. Threading is also something I'm trying to wrap my head around, so I'm happy to see i've gotten myself to the point of identifying it... how to make it multithreaded (or if it even should be) i will leave up to you all, but maybe I'll tackle it.

So, am I getting this right:
The point/advantage of having Listener implement IDisposable is so others can now call it in a using() (since using() requires the IDisposable interface) and trust it to clean up after itself. Does the IDisposable stuff also get called if, at some point in Program.cs, webServer = "null"? I think "yes".

Thank you, all, again.

#14 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 28 October 2010 - 01:32 PM

So, am I getting this right:
The point/advantage of having Listener implement IDisposable is so others can now call it in a using() (since using() requires the IDisposable interface) and trust it to clean up after itself. Does the IDisposable stuff also get called if, at some point in Program.cs, webServer = "null"? I think "yes".


Technically, no. The IDisposable interface establishes a standard convention for an object to declare that it has a special need to clean itself up (by implementing the IDisposable interface), and also the code that actually does the cleanup (the IDisposable.Dispose() method).

The reason it goes beyond using() is that there are other places where this is useful. For example, objects can reference other objects which can reference other objects still. The Dispose() method of the outermost object will want to call the Dispose() method of the objects it points to, and likewise they will want to dispose the objects they point to, even if there is no "using" statement involved.

Why have a standard interface? Why not call File.Close(), Timer.Shutdown(), IOPin.Release() and so on? Because IDisposable acts as a kind of documentation for both humans and computers to let them know in a standard way that this is an object that needs special disposing treatment. For example, the C# "foreach" operator will call Dispose() on the enumerator it is operating on when the loop is over, if that enumerator implements IDisposable. This is the only disciplined way that C# could implement such a feature... you can't expect foreach to go look up the documentation on your enumerator and find out that it needs to call "CloseMeNow" when it's done.

As to your webServer=null question, the answer is also technically "no". The finalize method (note: not the Dispose() method) might (might!) be called at some point after such an assignment, but you never know if or when. If a crude analogy helps, think of the difference between extinguishing your cigarette and throwing the butt it in the trash (Dispose) versus flicking the still-lit cigarette into the street (webServer=null). That cigarette gets extinguished and picked up by someone? eventually? doesn't it?

#15 bill.french

bill.french

    Advanced Member

  • Members
  • PipPipPip
  • 260 posts
  • LocationPrinceton, NJ

Posted 28 October 2010 - 11:09 PM

This has been great for me.

Corey, if I can get a little more time from you, or anyone else:

But you may be wondering why the link you posted has such complicated code. The answer is that Bill Gates is much smarter and richer than you and me, and therefore he has thought very hard about the difference between finalization and disposing. The rules are subtle and complicated (by the way, the link you posted also has it a little bit wrong)


Is the issue in:
        ~DisposeObject()

        {

            Dispose(false);

        }

? It seems this finalizer doesn't do anything, and based on what you said:
1. It should call CleanUp()
2. CleanUp() should deal with only unmanaged stuff
3. managed stuff should be handled in the if(disposing) block

Thanks, all, again. --Bill

#16 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 29 October 2010 - 04:33 AM

This has been great for me.

? It seems this finalizer doesn't do anything, and based on what you said:
1. It should call CleanUp()
2. CleanUp() should deal with only unmanaged stuff
3. managed stuff should be handled in the if(disposing) block


I think you have got it exactly right. :)

Just because I was feeling energetic, I wanted to reorg the sample code a little bit and cook up what I thought would be a reasonable pattern to use when there is inheritance involved. Here is what I came up with:

By the way, it's worth repeating that most C# objects don't need or want either a finalizer or a Dispose method. So you shouldn't use them on every object, just where your design calls for them.


  public class DisposeObject : IDisposable {
    private bool disposed = false;

    ~DisposeObject() {
      Dispose(false);
    }

    public void Dispose() {
      Dispose(true);
      //Give the GC a little break... if we've disposed the object,
      //then there's no need to bother finalizing it
      GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing) {
      if(disposed) {
        return;
      }
      DisposeHelper(disposing);
      disposed=true;
    }

    //your subclasses just need to override this.
    //they do their own disposing, and call base.DisposeHelper() *LAST*
    protected virtual void DisposeHelper(bool disposing) {
      if(disposing) {
        //-------------------------------
        //clean up managed resources here
        //-------------------------------        
      }

      //---------------------------------
      //clean up unmanaged resources here
      //---------------------------------
    }
  }

Then you can have

public class ChildObject : DisposeObject {
  protected override void DisposeHelper(bool disposing) {
    if(disposing) {
      //-------------------------------
      //clean up managed resources here
      //-------------------------------        
    }

    //---------------------------------
    //clean up unmanaged resources here
    //---------------------------------

    base.DisposeHelper(disposing); //important
  }
}

Hopefully I didn't mess that up.

#17 bill.french

bill.french

    Advanced Member

  • Members
  • PipPipPip
  • 260 posts
  • LocationPrinceton, NJ

Posted 30 October 2010 - 12:39 AM

Awesome, thank you, sir. Maybe in a couple weeks I can buy you a roast beef, mutz, and gravy sandwich when i'm in hoboken next.

#18 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 30 October 2010 - 01:05 AM

Awesome, thank you, sir. Maybe in a couple weeks I can buy you a roast beef, mutz, and gravy sandwich when i'm in hoboken next.


Wow, I have a new vocabulary word AND a meal to look forward to. You're on!




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.