你好,我遇到了以下代码的死锁问题。当我调用函数getMap()时会发生这种情况。但我无法重新看到可能导致这种情况的原因。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using AForge;
using AForge.Imaging;
using AForge.Imaging.Filters;
using AForge.Imaging.Textures;
using AForge.Math.Geometry;
namespace CDIO.Library
{
public class Polygon
{
List<IntPoint> hull;
public Polygon(List<IntPoint> hull)
{
this.hull = hull;
}
public bool inPoly(int x, int y)
{
int i, j = hull.Count - 1;
bool oddNodes = false;
for (i = 0; i < hull.Count; i++)
{
if (hull[i].Y < y && hull[j].Y >= y
|| hull[j].Y < y && hull[i].Y >= y)
{
try
{
if (hull[i].X + (y - hull[i].X) / (hull[j].X - hull[i].X) * (hull[j].X - hull[i].X) < x)
{
oddNodes = !oddNodes;
}
}
catch (DivideByZeroException e)
{
if (0 < x)
{
oddNodes = !oddNodes;
}
}
}
j = i;
}
return oddNodes;
}
public Rectangle getRectangle()
{
int x = -1, y = -1, width = -1, height = -1;
foreach (IntPoint item in hull)
{
if (item.X < x || x == -1)
x = item.X;
if (item.Y < y || y == -1)
y = item.Y;
if (item.X > width || width == -1)
width = item.X;
if (item.Y > height || height == -1)
height = item.Y;
}
return new Rectangle(x, y, width-x, height-y);
}
public Point[] getMap()
{
List<Point> points = new List<Point>();
lock (hull)
{
Rectangle rect = getRectangle();
for (int x = rect.X; x <= rect.X + rect.Width; x++)
{
for (int y = rect.Y; y <= rect.Y + rect.Height; y++)
{
if (inPoly(x, y))
points.Add(new Point(x, y));
}
}
}
return points.ToArray();
}
public float calculateArea()
{
List<IntPoint> list = new List<IntPoint>();
list.AddRange(hull);
list.Add(hull[0]);
float area = 0.0f;
for (int i = 0; i < hull.Count; i++)
{
area += list[i].X * list[i + 1].Y - list[i].Y * list[i + 1].X;
}
area = area / 2;
if (area < 0)
area = area * -1;
return area;
}
}
}
编辑: “使用System.Threading;”只是为了一些调试ealyer我们让thead睡了一下,我只是忘了删除它。
我们添加了“锁(船体)”以查看它是否可以修复死锁,它不会。 此程序也不会被多线程破坏,所以这不是问题。
我把它缩小到
中的错误if (inPoly(x, y))
points.Add(new Point(x, y));
错误消息
CLR无法过渡 从COM上下文0x1bb7b6b0到COM 上下文0x1bb7b900持续60秒。该 拥有目的地的线程 上下文/公寓是最有可能的 或者做一次非抽水等待或者 处理很长时间 没有泵Windows的操作 消息。这种情况一般都有 负面的业绩影响和可能 甚至导致应用程序成为 无响应或内存使用 随着时间的推移不断积累。至 一切都避免这个问题 线程公寓(STA)线程 应该使用抽等待原语 (例如CoWaitForMultipleHandles)和 经常在长时间内发送消息 正在运行。
答案 0 :(得分:4)
这是一个托管调试助手警告,与在线程上使用COM服务器有关。 COM的一个特性是它可以自动处理不支持多线程的组件的线程。它会自动将后台线程中的方法调用封送到UI线程,以便不以线程不安全的方式使用该组件。这是完全自动的,你不要自己编写任何代码来实现这一点。
为了使其正常工作,UI线程必须处于空闲状态,以便它可以执行方法调用。警告告诉您,UI线程不已空闲一分钟,它会阻止呼叫完成。最可能的原因是UI线程阻塞,等待线程完成。这永远不会发生,它已陷入僵局。或者它可能只是忙于运行该分钟的代码,从来没有绕过正常的职责,抽取消息循环。不抽取消息循环可防止编组呼叫完成并跳过警告。
应该很容易看到,应该冻结应用程序的主窗口并在标题栏中显示“无响应”消息。当您使用Debug + Break All,Debug + Windows + Threads并切换到UI线程,然后查看调用堆栈,您应该看到UI线程死锁的位置。通过不让UI线程在线程上等待或避免在工作线程上使用COM组件来修复它。如果它完全不合适(不应该),那么您可以使用Debug + Exceptions关闭警告。
这是警告的技术解释。无聊的是,Visual Studio 2005的RTM版本中存在一个错误。调试器出了问题,它往往在单步执行或检查变量时跳过MDA。已在Service Pack 1中修复,如果尚未执行此操作,请务必下载并安装它。
答案 1 :(得分:1)
在这个msdn article中,他们解释了为什么最好定义一个仅在lock语句中使用的变量。显然,它避免了很多这类问题。
答案 2 :(得分:0)
您在getMap()中锁定实例“hull”,然后在调用getRectangle()时锁定;你试图通过“船体”进行枚举。