我有一个听众:
listener = new HttpListener();
listener.Prefixes.Add(@"http://+:8077/");
listener.Start();
listenerThread = new Thread(HandleRequests);
listenerThread.Start();
我正在处理请求:
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
}
我想用这样的方式写 void Stop()
:
-
它将阻塞,直到所有当前处理的请求结束(即等待所有线程到"do some stuff") .
-
虽然它将等待已经开始的请求,但它将不允许任何更多的请求(即在
ListenerCallback
的开头返回) . -
之后它将调用
listener.Stop()
(listener.IsListening
变为false) .
怎么可能写?
EDIT :您对此解决方案有何看法?安全吗?
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();
}
}
5 回答
为了完整性,如果您管理自己的工作线程,它会是什么样子:
那么有几种方法可以解决这个问题...这是一个简单的例子,它使用信号量来跟踪正在进行的工作,以及在所有 Worker 完成时引发的信号 . 这应该给你一个基本的想法来工作 .
下面的解决方案并不理想,理想情况下我们应该在调用BeginGetContext之前获取信号量 . 这使关闭变得更加困难,所以我选择使用这种更简化的方法 . 如果我这样做是为了'真实',我可能会编写自己的线程管理而不是依赖ThreadPool . 这将允许更可靠的关闭 .
无论如何这里是完整的例子:
我在EDIT的一部分问题中咨询了我的代码,我决定接受一些修改:
只需调用listener.Stop()即可 . 这不会终止已经 Build 的任何连接,但会阻止任何新连接 .
这使用BlockingCollection类型的队列来为请求提供服务 . 它可以原样使用 . 您应该从这个派生一个类并覆盖Response .
这是如何使用它的示例 . 无需使用事件或任何锁定块 . BlockingCollection解决了所有这些问题 .