Модераторы: gambit, Partizan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Завершение потока и Invoke, Поток не хочет завершаться 
:(
    Опции темы
amarenkov
Дата 28.4.2008, 10:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 21.2.2008
Где: Воронеж

Репутация: нет
Всего: нет



Добрый день.

У меня во вторичном потоке происходят какие-то действия и иногда вызывается следующая функция:
Код

  private void OnDCRefreshImage(object sender)
        {
            if (!fobj_picture.InvokeRequired)
            {
               //Здесь даже может ничего не делаться...
            }
            else
            {   
                fobj_picture.Invoke(new MethodInvoker(delegate { OnDCRefreshImage(sender); }));
            }
        }


На закрытии формы я выставляю вторичному потоку флаг на завершение. Если строчка с fobj_picture.Invoke закоментарена, то все нормально завершается. Если нет, то второй поток продолжает висеть и не завершается вообще никогда. 

Возможно кто-то знает, в чем дело?

Заранее спасибо. 

Это сообщение отредактировал(а) amarenkov - 28.4.2008, 11:00
PM MAIL ICQ   Вверх
mr.DUDA
Дата 28.4.2008, 11:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 24
Всего: 232



Очень похоже на deadlock. Гуишный поток говорит второму потоку "завершайся" и ждёт, пока тот не завершится одним из способов (через событие, WaitHandle, проверкой IsAlive или Join-ом). В это время второй поток безуспешно пытается вызвать Invoke, который попросту не может выполниться т.к. Invoke основан на очереди оконных сообщений и не выполнится пока гуишный поток не выйдет из ожидания. Примерно так.

Выходом может быть вызов из гуишного потока thread.Abort и thread.Join(таймаут) второму потоку. В корневой функции второго потока нужно поставить try..catch(ThreadAbortException), чтобы сообщение об ошибке не вылетало.


--------------------
user posted image
PM MAIL WWW   Вверх
amarenkov
Дата 28.4.2008, 11:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 21.2.2008
Где: Воронеж

Репутация: нет
Всего: нет



mr.DUDA, у меня немного не так организовано приложение.

Вторичный поток крутится в бесконечном цикле, проверяя некоторый флаг. Когда флаг становится в true, вторичный поток просто завершает свою процедуру и завершается сам.

То есть, в основном потоке завершение вторичного потока выглядит просто как установка флага в true. После чего, основной поток продолжает свое завершение.

Есть подозрение, что в тот момент, когда вторичный поток делает Invoke, основного потока уже нет smile. Может такое быть? Как на это проверить?
PM MAIL ICQ   Вверх
mr.DUDA
Дата 28.4.2008, 13:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 24
Всего: 232



Если основной поток завершился, Invoke рухнет с исключением. Проверить можно поставив try..catch во втором потоке.

Кстати, ещё можно запустить в отладке, дойти до места где виснет и нажать "паузу" отладчика. В окне Debug/Windows/Threads посмотреть какие потоки выполняются и даблкликом пройтись по ним - покажет в каком месте в исходнике сейчас находится каждый поток.


--------------------
user posted image
PM MAIL WWW   Вверх
amarenkov
Дата 28.4.2008, 13:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 21.2.2008
Где: Воронеж

Репутация: нет
Всего: нет



mr.DUDA, сделал Abort и Join. Поток завершился, но исключения не вылетело. Что это может значить?

Добавлено через 2 минуты и 29 секунд
Хм, показывает, что второй поток стоит на строчке 
Код

fobj_picture.Invoke(new MethodInvoker(delegate { OnDCRefreshImage(sender); }));

и ни с места smile.

Добавлено через 5 минут и 9 секунд
Сделал так:
Код

MethodInvoker mi = new MethodInvoker(delegate { OnDCRefreshImage(sender); });
fobj_picture.Invoke(mi);

Стоит мертво на fobj_picture.Invoke(mi);
PM MAIL ICQ   Вверх
mr.DUDA
Дата 28.4.2008, 13:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 24
Всего: 232



А в анонимный метод заходит? Я бы вынес для отладки OnDCRefreshImage в отдельный метод и передавал делегат на него.


--------------------
user posted image
PM MAIL WWW   Вверх
amarenkov
Дата 28.4.2008, 14:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 21.2.2008
Где: Воронеж

Репутация: нет
Всего: нет



Вынес. Нет, не заходит. Когда жму на паузу и смотрю данные объектов, то во всех полях fobj_picture написано, дескать "Текущий поток спит, ждет или джоин".

Вообще в Threads видно 7 каких-то потоков. Один - мой вторичный. Главный поток имел ID 3704. Так в момент подвеса этого потока уже вообще не видать в списке потоков. Он завершился что ли?

PM MAIL ICQ   Вверх
amarenkov
Дата 28.4.2008, 15:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 21.2.2008
Где: Воронеж

Репутация: нет
Всего: нет



Чуть подробнее о вторичном потоке.

Основная функция:
Код

public void Draw()
        {
                fobj_mutex = new Mutex();
                fobj_arEvent = new AutoResetEvent(false);

                while (true)
                {
                    switch (fenm_drawState)
                    {
                        case EMDThreadState.edtsReStart:
                            // Всякое рисование
                            break;
                        case EMDThreadState.edtReSized:
                            OnResize();

                            fenm_drawState = EMDThreadState.edtsReStart;
                            break;
                        case EMDThreadState.edtAbort: return;
                        default: fobj_arEvent.WaitOne(); break;
                    }
                }           
        }


Пытаюсь его выключить:
Код

fobj_mapDraw.DrawState = CMapDraw.EMDThreadState.edtAbort;


Получается описанная выше проблема. Нашел такое еще решение:
Код

public void Exit()
        {
            fobj_mapDraw.DrawState = CMapDraw.EMDThreadState.edtAbort;
            while (fobj_mapDraw.Thread.IsAlive)
                Application.DoEvents();
         }


т.е. пока вторичный поток не завершится, основной обрабатывает свои сообщения. Так делать нормально вообще?

Второй вариант:
Код

public void Exit()
        {
            fobj_mapDraw.DrawState = CMapDraw.EMDThreadState.edtAbort;
            fobj_mapDraw.Thread.Abort();
            fobj_mapDraw.Thread.Join();
        }


Тоже работает корректно - поток завершается. Никаких исключений не вызывается. Но мне как-то этот вариант не нравится.
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Разработка Windows Forms | Следующая тема »


 




[ Время генерации скрипта: 0.0690 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.