Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi-threading with .Net HttpListener

I have a listener:

listener = new HttpListener(); listener.Prefixes.Add(@"http://+:8077/"); listener.Start(); listenerThread = new Thread(HandleRequests); listenerThread.Start(); 

And I am handling requests:

private void HandleRequests() {     while (listener.IsListening)     {         var context = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);         context.AsyncWaitHandle.WaitOne();     } }  private void ListenerCallback(IAsyncResult ar) {     var listener = ar.AsyncState as HttpListener;      var context = listener.EndGetContext(ar);      //do some stuff } 

I would like to write void Stop() in such a way, that:

  1. It will block until all currently handled requests will end (ie. will wait for all threads to "do some stuff").
  2. While it will wait for already started requests, it will not allow any more requests (ie. return at the beginning of ListenerCallback).
  3. After that it will call listener.Stop() (listener.IsListening became false).

How could it be write?

EDIT: What do you think about this solution? Is it safe?

public void Stop()  {     lock (this)     {         isStopping = true;     }     resetEvent.WaitOne(); //initially set to true     listener.Stop(); }  private void ListenerCallback(IAsyncResult ar) {     lock (this)     {         if (isStopping)             return;          resetEvent.Reset();         numberOfRequests++;     }      var listener = ar.AsyncState as HttpListener;      var context = listener.EndGetContext(ar);      //do some stuff      lock (this)     {         if (--numberOfRequests == 0)             resetEvent.Set();     } } 
like image 806
prostynick Avatar asked Jan 12 '11 17:01

prostynick


1 Answers

For completeness, here is what it would look like if you manage your own worker threads:

class HttpServer : IDisposable {     private readonly HttpListener _listener;     private readonly Thread _listenerThread;     private readonly Thread[] _workers;     private readonly ManualResetEvent _stop, _ready;     private Queue<HttpListenerContext> _queue;      public HttpServer(int maxThreads)     {         _workers = new Thread[maxThreads];         _queue = new Queue<HttpListenerContext>();         _stop = new ManualResetEvent(false);         _ready = new ManualResetEvent(false);         _listener = new HttpListener();         _listenerThread = new Thread(HandleRequests);     }      public void Start(int port)     {         _listener.Prefixes.Add(String.Format(@"http://+:{0}/", port));         _listener.Start();         _listenerThread.Start();          for (int i = 0; i < _workers.Length; i++)         {             _workers[i] = new Thread(Worker);             _workers[i].Start();         }     }      public void Dispose()     { Stop(); }      public void Stop()     {         _stop.Set();         _listenerThread.Join();         foreach (Thread worker in _workers)             worker.Join();         _listener.Stop();     }      private void HandleRequests()     {         while (_listener.IsListening)         {             var context = _listener.BeginGetContext(ContextReady, null);              if (0 == WaitHandle.WaitAny(new[] { _stop, context.AsyncWaitHandle }))                 return;         }     }      private void ContextReady(IAsyncResult ar)     {         try         {             lock (_queue)             {                 _queue.Enqueue(_listener.EndGetContext(ar));                 _ready.Set();             }         }         catch { return; }     }      private void Worker()     {         WaitHandle[] wait = new[] { _ready, _stop };         while (0 == WaitHandle.WaitAny(wait))         {             HttpListenerContext context;             lock (_queue)             {                 if (_queue.Count > 0)                     context = _queue.Dequeue();                 else                 {                     _ready.Reset();                     continue;                 }             }              try { ProcessRequest(context); }             catch (Exception e) { Console.Error.WriteLine(e); }         }     }      public event Action<HttpListenerContext> ProcessRequest; } 
like image 69
csharptest.net Avatar answered Sep 28 '22 01:09

csharptest.net