Проблема взаимоблокировки

Здравствуйте, у меня проблема с тупиком со следующим кодом. Это происходит, когда я вызываю функцию 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;» было просто для некоторой отладки, когда мы заставили рекламу немного заснуть, я просто забыл ее удалить.

Мы добавили «замок (корпус)», чтобы посмотреть, может ли он исправить мертвую блокировку, но это не так. Также программа не работает с многопоточностью, так что это не проблема.

Я сократил это до ошибки, возникающей в

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

Сообщение об ошибке

CLR не удалось перейти из контекста COM 0x1bb7b6b0 в контекст COM 0x1bb7b900 в течение 60 секунд. Поток, который владеет целевым контекстом/квартирой, скорее всего, либо выполняет ожидание без перекачки, либо обрабатывает очень длительную операцию без перекачки сообщений Windows. Эта ситуация обычно оказывает негативное влияние на производительность и может даже привести к тому, что приложение перестанет отвечать на запросы или использование памяти постоянно накапливается с течением времени. Чтобы избежать этой проблемы, все потоки однопотокового подразделения (STA) должны использовать примитивы ожидания перекачки (такие как CoWaitForMultipleHandles) и регулярно перекачивать сообщения во время длительных операций.


person Androme    schedule 28.04.2010    source источник
comment
Вы ссылаетесь на System.Threading, но я не вижу ничего из того, что используется в этом пространстве имен. Вы крутите какие-то темы где-то в другом месте? Если да, то какие методы они вызывают у Polygon?   -  person Daniel Renshaw    schedule 28.04.2010
comment
Это на самом деле (каким-то образом) тупик базы данных? Можете ли вы опубликовать точное сообщение об ошибке и, если возможно, трассировку стека?   -  person Daniel Renshaw    schedule 28.04.2010
comment
Это проблема COM-взаимодействия, поэтому я добавил этот тег к вашему вопросу.   -  person Daniel Renshaw    schedule 28.04.2010


Ответы (3)


Это предупреждение помощника управляемой отладки, касающееся использования COM-серверов в потоке. Одной из особенностей COM является то, что он автоматически обрабатывает многопоточность для компонентов, которые не поддерживают многопоточность. Он автоматически маршалирует вызов метода из фонового потока в поток пользовательского интерфейса, чтобы компонент не использовался небезопасным для потоков способом. Это полностью автоматически, вы не пишете никакого кода, чтобы это произошло.

Чтобы это работало правильно, поток пользовательского интерфейса должен бездействовать, чтобы он мог выполнить вызов метода. Предупреждение сообщает вам, что поток пользовательского интерфейса не бездействовал в течение минуты, что препятствует завершению вызова. Наиболее вероятной причиной этого является то, что поток пользовательского интерфейса блокируется, ожидая завершения потока. Этого никогда не будет, это зашло в тупик. Или он мог просто быть занят выполнением кода в течение этой минуты, никогда не выполняя свои обычные обязанности, прокачивая цикл сообщений. Отсутствие прокачки цикла сообщений предотвращает завершение упорядоченного вызова и выводит предупреждение.

Это должно быть хорошо видно, главное окно вашего приложения должно быть заморожено и отображать сообщение «Не отвечает» в строке заголовка. Когда вы используете Debug + Break All, Debug + Windows + Threads и переключаетесь на поток пользовательского интерфейса, затем посмотрите на стек вызовов, вы должны увидеть место, где поток пользовательского интерфейса заблокирован. Исправьте это, не заставляя поток пользовательского интерфейса ждать в потоке или избегая использования компонента COM в рабочем потоке. Если это совершенно неуместно (не должно быть), вы можете отключить предупреждение с помощью Debug + Exceptions.

Это техническое объяснение предупреждения. Скучным является то, что в RTM-версии Visual Studio 2005 была ошибка. Что-то не так с отладчиком, он имел тенденцию отключать MDA во время одиночного шага или проверки переменных. Это было исправлено в Service Pack 1, обязательно скачайте и установите его, если вы еще этого не сделали.

person Hans Passant    schedule 28.04.2010
comment
Я исправил проблему, запустив алгоритм в отдельном потоке. - person Androme; 05.05.2010

в этой msdn статье объясняется, почему лучше определять только переменную используется в операторе блокировки. Ясно, что это позволяет избежать многих проблем такого рода.

person PierrOz    schedule 28.04.2010

Вы блокируете экземпляр «корпус» в getMap(), а затем, когда вы вызываете getRectangle(); вы пытаетесь перечислить через "корпус".

person bleeeah    schedule 28.04.2010
comment
Но getRectangle() вызывается в том же потоке, поэтому блокировка не блокирует перечисление простого списка, не так ли? - person Daniel Renshaw; 28.04.2010
comment
повторение заблокированного списка‹› в том же потоке не проблема. - person Henk Holterman; 28.04.2010