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

Question regarding listeningSocket.Accept();


  • Please log in to reply
3 replies to this topic

#1 bill.french

bill.french

    Advanced Member

  • Members
  • PipPipPip
  • 260 posts
  • LocationPrinceton, NJ

Posted 08 November 2010 - 10:25 PM

Regarding Fred's webserver -- and other things of this sort that use
listeningSocket.Accept();

How do you kill them if you want them to stop listening? They are in their own threads, waiting for connections. How to you tell it to stop accepting connections, and also make the thread to go away?

My question is actually more about how to do this in general, and not specific to the web server, but it is an example of what I'm trying to understand. Thanks!

#2 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 09 November 2010 - 05:13 AM

One way is to call t.Abort() where t is the Thread in question. This will cause the victim to experience a ThreadAbortException. (Which, by the way, is a funky little exception -- see note 1)

However, I consider it kind of dirty, because it makes it that much harder to analyze the correctness of your program. If you use it, you have to consider that the target code might be getting a ThreadAbortException at some arbitrary and unplanned-for point, and it's not hard to imagine scenarios where this could mess up your program's global state.

Unfortunately, in the webserver program I don't see any other way to abort the Accept. One reason I don't like calling Abort() is that you might get in a little race and the webserver might receive a new connection just as you've decided to abort it, so maybe what really gets aborted is not the Accept() itself but rather some other point while you're halfway through the "requestReceived" delegate and whatever it was trying to do. At the very least this is ugly.

In general the approach I like to use in my threads is some variant of the below:

while(I still have more work to do) {
  ...do some work...
  if(killRequested) {
    //maybe do some cleanup here
    break; 
  }
}

In code like this, you request that it die (by setting some shared killRequested flag), but it dies at a time of its own choosing.

Now, if I absolutely had to support this in the case of the webserver, my first instinct is the following (maybe someone out there has a simpler idea). Make a new thread and dedicate it solely to calling Accept and stashing its result somewhere, like this:

while(true) {
  try {
    var nextSocket=listeningSocket.Accept();
    lock(sync) {
      queue.Add(nextSocket);
    }
    autoResetEvent.Set(); //notify my listener that there is a new item
  } catch(ThreadAbortException) { //consider maybe doing this on *any* exception
    lock(sync) {
      queue=null;
    }
    autoResetEvent.Set(); //notify my listener one last time
  }
}

The nice thing about this is that it's not doing very much, so it's easier to analyze its behavior upon thread abort. Upon thread abort, I even throw away my queue (because maybe the thread abort happened at the worst possible time and corrupted my queue data structure. I don't know whether that's possible or not given the thread model of the Netduino but I'm erring on the side of caution)

Then on the queue consuming side you have this thread:

while(true) {
  var killRequested=false;
  Socket nextItem=null;
  lock(sync) {
    if(queue==null) {
      killRequested=true;
    } else if(queue.Length()>0) {
      nextItem=(Socket)queue.Dequeue();
    }
  }
  if(killRequested) {
    ...nice kill of self here
    return;
  }
  if(nextItem==null) {
    //wait for a signal and then restart the logic all over again
    autoResetEvent.WaitOne();
    continue;
  }
  ...otherwise we have something to work on
}

The nice thing about this thread is that nobody aborts it. It hears about the death of the acceptor thread and then kills itself at a controlled time, not while it's in the middle of something.

Is this post helpful? Too long and wanky? You decide!


Note 1: The trippy thing about ThreadAbortException is that you can catch it but it gets rethrown at the end of every catch. You may want to run this little program and puzzle over all the "wow"'s that get printed and why it doesn't print "Why am I not printed?", and how this is different from normal exception handling.

using System;
using System.Threading;
using Microsoft.SPOT;

namespace NetduinoApplication1 {
  public class Program {
    public static void Main() {
      var t=new Thread(Doit1);
      t.Start();
      Thread.Sleep(5*1000);
      t.Abort();
    }

    private static void Doit1() {
      try {
        Doit2();
      } catch(Exception) {
        Debug.Print("wow 1");
      }
    }

    private static void Doit2() {
      try {
        Doit3();
      } catch(Exception) {
        Debug.Print("wow 2");
      }
    }

    private static void Doit3() {
      try {
        while(true) {
          Thread.Sleep(100);
        }
      } catch(Exception) {
        Debug.Print("wow 3");
      }
      Debug.Print("Why am I not printed?");
    }
  }
}


#3 Fred

Fred

    Advanced Member

  • Members
  • PipPipPip
  • 302 posts
  • LocationUK

Posted 09 November 2010 - 06:30 AM

A very informative post. Threading is a pain in the ass and best avoided if you can for all the reasons above. Debugging can be a real problem in a full size multi threaded application. If you're working with the standard framework the new parallel library is worth looking at. Keeps you away from all these implementation details.

#4 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 09 November 2010 - 06:49 AM

It's also possible (I have not checked this in the docs and the webserver isn't working for me at the moment) that if you call listeningSocket.Dispose() it will immediately throw an exception on all the other threads that are waiting on listeningSocket.Accept(). If that's the way it works (as it does in my pony-complete world), then you could discard all my jibber jabber above.




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.