C# 关于线程和I/O流的问题
本帖最后由 u011919488 于 2013-09-11 14:31:57 编辑 用一个窗体(以下称A窗体)中的线程检测第三方设备的数据 有数据则打开另一个窗体(B窗体,只打开一个)
B窗体中 有一个System.Threading.Timer 用来监听(HttpListenerContext)数据流
同时还有一个timer控件 控制窗体抖动 我在关闭这个窗体的时候 会报 “由于线程退出或应用程序请求,已中止 I/O 操作”(如果不使用监听数据流线程则没问题)
代码如下:
//监听按键信息
System.Threading.Timer threadTimer;
/// <summary>
/// 开启监听
/// </summary>
private void StartListen()
{
threadTimer = new System.Threading.Timer(new TimerCallback(CatchTelNumber), null, 1000, 500);
listerner.AuthenticationSchemes = AuthenticationSchemes.Anonymous;//指定身份验证 Anonymous匿名访问
listerner.Prefixes.Add("http://localhost:4529/login/");
listerner.Start();
}
/// <summary>
/// 获取按键信息
/// </summary>
/// <param name="state"></param>
private void CatchTelNumber(object state)
{
_th = new Thread(new ThreadStart(() =>
{
//等待请求连接
//没有请求则GetContext处于阻塞状态
lock (_lock)
{
HttpListenerContext ctx = listerner.GetContext();
ctx.Response.StatusCode = 200;//设置返回给客服端http状态代码
string name = ctx.Request.QueryString["c_meb_no"];
if (name != null)
{
catchKey.Append(name);
SetBtnEnable(name);
using (StreamWriter writer = new StreamWriter(ctx.Response.OutputStream))
{
writer.WriteLine("<html><head><title>WebServer</title></head><body>");
writer.WriteLine("<div>hello{0}</div>", name);
writer.WriteLine("</body></html>");
writer.Close();
ctx.Response.Close();
}
}
}
}));
_th.IsBackground = true;
_th.Start();
}
/// <summary>i/o 线程
/// 关闭窗体
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void pictureBox1_Click(object sender, EventArgs e)
{
Cl = null;
Ph = null;
threadTimer.Dispose();
listerner.Stop();
this.Dispose();
}
[解决办法]
CatchTelNumber 里面的方法不用线程看看呢?
里面的线程是多余的.
[解决办法]
threadTimer.Dispose();
listerner.Stop();
这两句顺序换一下看看.
[解决办法]
这段代码的逻辑有问题,为什么要开那么多线程?
你现在每半秒开一个线程,除了第一线程可以进入lock以外,其它线程都在lock处等待。
第一线程将在listerner.GetContext()处等待,直到出现满足条件的http请求。
这时候第一线程可以顺利执行完毕,第二线程进入lock,在listerner.GetContext()处等待,其它线程继续在lock处等待。
如果这时候 listerner.Stop(),则第二线程(监听listener的线程)异常退出(由于应用程序请求)。第三线程进入lock,在调用listerner.GetContext()的时候,产生异常InvalidOperationException:请在调用此方法前调用 Start() 方法,然后第四第五线程重复这个过程,直到所有线程都异常退出。