死锁问题

发布于 2024-08-30 13:01:07 字数 3792 浏览 5 评论 0原文

您好,我遇到以下代码的死锁问题。当我调用函数 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;”只是为了早些时候进行一些调试,我们让 thead 休眠了一下,我只是忘记将其删除。

我们添加了“锁(船体)”来看看它是否可以修复死锁,但它没有。 此外,该程序不是以多线程运行的,所以这不是问题。

中出现的错误

if (inPoly(x, y))
    points.Add(new Point(x, y));

我已将其缩小到错误消息

CLR 无法转换 从 COM 上下文 0x1bb7b6b0 到 COM 上下文 0x1bb7b900 60 秒。这 拥有目的地的线程 上下文/公寓最有可能 要么进行非抽水等待,要么 处理很长时间的运行 无需泵送 Windows 即可运行 消息。这种情况一般有 负面的性能影响,并可能 甚至导致应用程序变得 无响应或内存使用 随着时间的推移不断积累。到 避免这个问题,全部单身 线程单元 (STA) 线程 应该使用泵等待原语 (例如 CoWaitForMultipleHandles)和 在长时间内定期发送消息 运行操作。

Hello i'm having a deadlock problem with the following code. It happens when i call the function getMap(). But i can't reealy see what can cause this.

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;
        }
    }
}

EDIT:
The "using System.Threading;" was just for some debugging ealyer where we made the thead sleep a bit, i just forgot to remove it.

We added the "lock(hull)" to see if it could fix the dead lock, it diden't.
Also the program is not runed with multi threading, so that is not the problem.

I have narroed it down to the error accuring in

if (inPoly(x, y))
    points.Add(new Point(x, y));

The error message

The CLR has been unable to transition
from COM context 0x1bb7b6b0 to COM
context 0x1bb7b900 for 60 seconds. The
thread that owns the destination
context/apartment is most likely
either doing a non pumping wait or
processing a very long running
operation without pumping Windows
messages. This situation generally has
a negative performance impact and may
even lead to the application becoming
non responsive or memory usage
accumulating continually over time. To
avoid this problem, all single
threaded apartment (STA) threads
should use pumping wait primitives
(such as CoWaitForMultipleHandles) and
routinely pump messages during long
running operations.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

甜`诱少女 2024-09-06 13:01:07

这是一个托管调试助手警告,与在线程上使用 COM 服务器有关。 COM 的特性之一是它自动为不支持多线程的组件处理线程。它自动将方法调用从后台线程编组到 UI 线程,以便组件不会以线程不安全的方式使用。这是完全自动的,您不需要自己编写任何代码来实现这一点。

为了使其正常工作,UI 线程必须处于空闲状态,以便它可以执行方法调用。该警告告诉您 UI 线程没有空闲一分钟,这会阻止调用完成。最可能的原因是 UI 线程正在阻塞,正在等待线程完成。这永远不会发生,它陷入了僵局。或者它可能只是在那一分钟忙于运行代码,从来没有抽出时间来执行其正常职责,即泵送消息循环。不泵送消息循环会导致编组调用无法完成并引发警告。

这应该很容易看到,应用程序的主窗口应该被冻结并在标题栏中显示“未响应”消息。当你使用 Debug + Break All、Debug + Windows + Threads 并切换到 UI 线程,然后查看调用堆栈时,你应该看到 UI 线程死锁的地方。通过不让 UI 线程在该线程上等待或避免在工作线程上使用 COM 组件来修复此问题。如果它完全不合适(不应该),那么您可以使用“调试+异常”关闭警告。

这是该警告的技术解释。令人厌烦的是,Visual Studio 2005 的 RTM 版本中存在一个错误。调试器出了问题,它在单步执行或检查变量时往往会导致 MDA 出错。该问题已在 Service Pack 1 中得到修复,如果您尚未下载并安装它,请务必下载并安装它。

It is a Managed Debugging Assistant warning, relating to using COM servers on a thread. One of the features of COM is that it automatically handles threading for components that do not support multi-threading. It automatically marshals a method call from a background thread to the UI thread so that the component isn't used in a thread-unsafe manner. This is completely automatic, you don't write any code yourself to make this happen.

For this to work properly, the UI thread must be idle so that it can execute the method call. The warning tells you that the UI thread has not been idle for a minute, it prevents the call from completing. The most likely reason for that is that the UI thread is blocking, waiting for the thread to complete. That will never happen, it is deadlocked. Or it could just have been busy running code for that minute, never getting around to doing its normal duties, pumping the message loop. Not pumping the message loop prevents the marshaled call from completing and trips the warning.

This should be readily visible, the main window of your app should be frozen and display the "Not Responding" message in the title bar. When you use Debug + Break All, Debug + Windows + Threads and switch to the UI thread, then look at the call stack, you should see the place where the UI thread is deadlocked. Fix it by not making the UI thread wait on the thread or by avoiding using the COM component on a worker thread. If it is completely inappropriate (shouldn't be) then you can turn off the warning with Debug + Exceptions.

That's the technical explanation for the warning. The boring one is that there was a bug in the RTM version of Visual Studio 2005. Something wrong with the debugger, it tended to trip the MDA while single stepping or inspecting variables. That got fixed in Service Pack 1, be sure to download and install it if you haven't done this yet.

沦落红尘 2024-09-06 13:01:07

在这篇 msdn 文章 中,他们解释了为什么最好只定义一个变量在lock语句中使用。显然,它避免了很多此类问题。

in this msdn article they explain why it's better to define a variable only used in the lock statement. Clearly it avoids a lot of problem of that kind.

煞人兵器 2024-09-06 13:01:07

您在 getMap() 中锁定实例“hull”,然后当您调用 getRectangle(); 时您正在尝试通过“hull”进行枚举。

You are locking on the instance "hull" in getMap() and then when you call getRectangle(); you are attempting to enumerate through "hull".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文