Exception в другом потоке
От: Chez Россия  
Дата: 03.06.05 07:30
Оценка: +1
Привет.

Сюжет. Работает поток A, исполняющий большой объём кода (рассчёт чего-либо). На любом этапе нужно обновлять пользовательский интерфейс — сообщать о текущем состоянии процесса, обрабатывать Cancel.
Из-за этого в очень многих местах приходится вставлять код вроде
m_pUICtx->UpdateStatus(currentStage, currentPercent, ...);
if (m_pUICtx->IsCancelled())
{
   cleanup();
     return ...;
}

Предложение.
Это плохо. Мне пришла в голову хорошая идея.
Если можно было бы из внешнего UI-потока B вытолкнуть исключение, которое отработаыло бы в контексте потока A, то можно было бы такие вещи творить!
Весь код потока A можно было бы очистить от кода связанного с UI.
При возникновении исключения на любом этапе наступает Cancel. Если нужно, поток A может перехватить это исключение чтобы сделать нужные подчистки.

Для обновления состояния UI можно было бы использовать SEH исключения:

поток A

int report_progress(int i)
{
    pUICtx->Update(i);
    return EXCEPTION_CONTINUE_EXECUTION;
}

void A_worker()
{
    int i = 0;

    __try
    {
        i++;
        // здесь внешний код вызывает UpdateUI_Exception
        i++;
        i++;
        ...
    }
    __except(report_progress(i))
    {
    }
}


Идея мне очень понравилась. На её основе можно было бы решить множество красивых задач — обработка UI это самая очевидня среди них.

Собственно, вопрос: можно ли как-то вытолкнуть исключение (C++ и\или SEH) в другом потоке?

Chez, ICQ#161095094

Posted via:RSDN@Home;version:1.1.3;muzikstamp:silent

Re: Exception в другом потоке
От: Patalog Россия  
Дата: 03.06.05 08:34
Оценка: +1
Здравствуйте, Chez, Вы писали:

[]

C>Это плохо. Мне пришла в голову хорошая идея.


Не думаю.
C>Если можно было бы из внешнего UI-потока B вытолкнуть исключение, которое отработаыло бы в контексте потока A, то можно было бы такие вещи творить!

Посмотри в сторону ATL механизма thunk и GetThreadContext/SetThreadContext. Т.е. делаем SuspendThread, правим EIP на ф-ю котор. кидает исключения, а потом ResumeThread.
Но все это чистое хакерство, кроме того весьма граблеопасное. Так что вещей можно действительно натворить. Тут уже эта тема всплывала, поищи.

А не проще ли

C>

C>поток A

C>void report_progress(int i)
C>{
C>    pUICtx->Update(i);
C>}

C>void A_worker()
C>{
C>    int i = 0;

C>    {
C>        i++;
            // здесь внешний код ставит флажок (синхр. опущена для простоты)
            if (some_ui_flag)
            {
                pUICtx->Update(i)
                //сбросим флажек
            }
                
C>        i++;
C>        i++;
C>        ...
C>    }
C>}
C>
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Почетный кавалер ордена Совка.
Re[2]: Exception в другом потоке
От: Chez Россия  
Дата: 03.06.05 09:08
Оценка:
Здравствуйте, Patalog, Вы писали:

C>>Это плохо. Мне пришла в голову хорошая идея.

P>Не думаю.


C>>Если можно было бы из внешнего UI-потока B вытолкнуть исключение, которое отработаыло бы в контексте потока A, то можно было бы такие вещи творить!

P>Посмотри в сторону ATL механизма thunk и GetThreadContext/SetThreadContext. Т.е. делаем SuspendThread, правим EIP на ф-ю котор. кидает исключения, а потом ResumeThread.
P>Но все это чистое хакерство, кроме того весьма граблеопасное. Так что вещей можно действительно натворить. Тут уже эта тема всплывала, поищи.
Ммм. А можно поподробнее? В MSDN связанно с thunks — тока какой-то страх с 16-битным кодом...
Это оно?

P>А не проще ли

Не проще. Чтобы не делать такого, всё и было задумано.

Chez, ICQ#161095094

Posted via:RSDN@Home;version:1.1.3;muzikstamp:silent

Re: Exception в другом потоке
От: Аноним  
Дата: 03.06.05 09:58
Оценка:
Здравствуйте, Chez, Вы писали:

C>Привет.


C>Сюжет. Работает поток A, исполняющий большой объём кода (рассчёт чего-либо). На любом этапе нужно обновлять пользовательский интерфейс — сообщать о текущем состоянии процесса, обрабатывать Cancel.

C>Из-за этого в очень многих местах приходится вставлять код вроде

.....

В данный момент я как раз решаю подобную задачу.
Разработал спец. метод и назвал его "Тикающая функция" (блин прям как "Парящий дракон")

смысл вот в чем:

work trhad:

DWORD HEART::Thread___Run(LPVOID pVoid)
{
    HEART* pMe = (HEART*)pVoid;
    UINT nCount = 0;
    BOOL bStopped = FALSE;
    while(!bStopped)
    {
        bStopped = pMe->m_bStop_Thread;
        if (!pMe->Tick(nCount, bStopped)) {break;}
        nCount++; 
    }
    return nCount;
}




UI thread:

void HEART::StartRunThread()
{
    ASSERT(!m_hThumbGen_Thread);    

    m_bStop_Thread = FALSE; // Disable stopping flag

    m_hThumbGen_Thread = CreateThread(NULL, 0, Thread___Run, this, THREAD_PRIORITY_IDLE, NULL);
    ResumeThread(m_hThumbGen_Thread); 
}

void HEART::StopRunThread(BOOL bIsTerminate)
{
    if (!m_hThumbGen_Thread) {return;}

    UINT nCounter = 0;
    DWORD dwExitCode = 0;

    m_bStop_Thread = TRUE;  // Enable stopping flag

    while (WaitForSingleObject(m_hThumbGen_Thread, 50) == WAIT_TIMEOUT)
    {
        GLB_pApp->ProcessMessages();// PumpMessage();
        if (nCounter > 100 && bIsTerminate) {TerminateThread(m_hThumbGen_Thread, dwExitCode);}
        nCounter++;
    }

    CloseHandle(m_hThumbGen_Thread);
    m_hThumbGen_Thread = NULL;
}





Создается трид в него передается указатель на объект, трид внутри содержит цикл каждый раз вызывающий ту самую Tick().
Tick() — многократно вызывемая функция, делающая за один такт очередной (НЕБОЛЬШОЙ ПО ВРЕМЕНИ) шаг в работе working thread.
Применительно к твему примеру могла бы делать Tick() {i++;}

после каждого такта в цикле проверяется флаг останова (апдейта, перенаправления и пр.), цикл остановится (отработает апдейт, перенаправление и пр.) если установить во внешнем объекте флаг.

Эта схема уже удачно применяется. И работает без нареканий.
Re[2]: Exception в другом потоке
От: Chez Россия  
Дата: 03.06.05 11:07
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Эта схема уже удачно применяется. И работает без нареканий.

А как в таком случае будет выглядеть реализация функции Tick()?

Chez, ICQ#161095094

Posted via:RSDN@Home;version:1.1.3;muzikstamp:silent

Re: Exception в другом потоке
От: Аноним  
Дата: 03.06.05 11:20
Оценка:
Я так понял ты просто хочеш оповестить главный поток о состояниях в рабочем потоке?
Это можно сделать с помощью посылки сообщений (PostMessage)
Тем самым ты избавляешь главный поток от необходимости постоянно опрашивать
рабочий поток.
Re[2]: Exception в другом потоке
От: Chez Россия  
Дата: 03.06.05 11:31
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Я так понял ты просто хочеш оповестить главный поток о состояниях в рабочем потоке?

А>Это можно сделать с помощью посылки сообщений (PostMessage)
А>Тем самым ты избавляешь главный поток от необходимости постоянно опрашивать
А>рабочий поток.
Да, но таким образом я заставляю рабочий поток постоянно уведомлять главный поток.
Сделать чтобы главной поток опрашивал — запросто.
А чтобы рабочий поток отпралял — нет: представьте что в нём задействован мегабайт исходников, вычисляющих что-либо.

И ввобще, код, связанный с алгоритмами, вачислениями и т.д. никакого отношения к UI иметь не должен. Он должен о нём просто не знать.

Chez, ICQ#161095094

Posted via:RSDN@Home;version:1.1.3;muzikstamp:silent

Re[3]: Exception в другом потоке
От: Patalog Россия  
Дата: 03.06.05 11:43
Оценка:
Здравствуйте, Chez, Вы писали:

хъ

C>Ммм. А можно поподробнее? В MSDN связанно с thunks — тока какой-то страх с 16-битным кодом...

C>Это оно?

Нет. См. напр. _stdcallthunk в atlbase.h. Также в местных форумах переодически эта тема всплывала в связи с "нестатический метод класса как оконная ф-я". Воообще-то оно тебе не для данной задачи не особо и надо, я ее пользовал в подобном случае сугубо для удобства.

P>>А не проще ли


C>Не проще. Чтобы не делать такого, всё и было задумано.


Ну не знаю. Вопрос вкуса наверное.
А ты, как я понял, вообще не ищещ легких путей и любишь подобные штучки на грани фола.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Почетный кавалер ордена Совка.
Re[3]: Exception в другом потоке
От: Patalog Россия  
Дата: 03.06.05 11:50
Оценка:
Здравствуйте, Chez, Вы писали:

хъ

C>А чтобы рабочий поток отпралял — нет: представьте что в нём задействован мегабайт исходников, вычисляющих что-либо.


C>И ввобще, код, связанный с алгоритмами, вачислениями и т.д. никакого отношения к UI иметь не должен. Он должен о нём просто не знать.


Хм, может тебе подумать в торону запустить этот мегавычислительный участок кода как отдельный отлаживаемый процеесс?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Почетный кавалер ордена Совка.
Re[4]: Exception в другом потоке
От: Chez Россия  
Дата: 03.06.05 12:53
Оценка:
Здравствуйте, Patalog, Вы писали:

P>Хм, может тебе подумать в торону запустить этот мегавычислительный участок кода как отдельный отлаживаемый процеесс?

Может. Можно поподробнее?

Chez, ICQ#161095094

Posted via:RSDN@Home;version:1.1.3;muzikstamp:silent

Re[3]: Exception в другом потоке
От: Аноним  
Дата: 03.06.05 13:27
Оценка:
Здравствуйте, Chez, Вы писали:

C>Здравствуйте, <Аноним>, Вы писали:


C>И ввобще, код, связанный с алгоритмами, вачислениями и т.д. никакого отношения к UI иметь не должен. Он должен о нём просто не знать.


Ну и что?
К UI это прямого отношения не имеет.
Тебе нужен механизм оповещения, который является
платформенно независимым и не привязанным к UI в этом самом рабочем потоке.
Это все нормально можно организовать.
Уж точно будет лучше выкидывания исключений....
Рабочий поток все равно должен оставлять какие-то следы
чтобы основной поток знал о них и мог бы как-то их визуализировать.
Если рабочий поток не оставляет следов и не шлет никаких сообщений,
то у тебя есть только момент начала работы и момент завершения работы потока.
В этом случае ничего другого ты не получишь и в UI ничего и не покажешь.
Re[5]: Exception в другом потоке
От: Patalog Россия  
Дата: 04.06.05 06:48
Оценка: 1 (1)
Здравствуйте, Chez, Вы писали:

[]

P>>Хм, может тебе подумать в торону запустить этот мегавычислительный участок кода как отдельный отлаживаемый процеесс?


C>Может. Можно поподробнее?


Посмотри на DebugBreakProcess (увы, но она только для ХР и далее). Т.е. запускаешь процесс как отлаживаемый, а когда тебе нужно обновление брякаешь его, ловишь исключение в WaitForDebugEvent читаешь нужные данные ReadProcessMemory и потом ContinueDebugEvent. Можно еще попробовать ловить отладочное исключение в самом рабочем процессе а потом предавать нужные данные via RaiseException либо OutputDebugString. Все это на гране, но тем не менее вполне легально. Еще можно попробовать SuspendThread, FlushInstructionCache, вписать int 3 с помощью WriteProcessMemory и ResumeThread. Но это уже хак, имхо.
Но это все гипотетически сам я ничего такого делать не пробовал.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Почетный кавалер ордена Совка.
Re: Exception в другом потоке
От: _nn_ www.nemerleweb.com
Дата: 04.06.05 07:21
Оценка: 1 (1)
Здравствуйте, Chez, Вы писали:

C>Привет.


C>Собственно, вопрос: можно ли как-то вытолкнуть исключение (C++ и\или SEH) в другом потоке?


Посмотрите Межпотоковое кидание исключений
Автор: adontz
Дата: 03.06.05
.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Exception в другом потоке
От: allco Лес http://www.asdevel.com
Дата: 06.06.05 20:20
Оценка:
Здравствуйте, Chez, Вы писали:

C>Здравствуйте, <Аноним>, Вы писали:


А>>Эта схема уже удачно применяется. И работает без нареканий.

C>А как в таком случае будет выглядеть реализация функции Tick()?

Эта функция за каждый такт выполняет очердной этап решаемой задачи (если надо обработать кучу файлов, к примеру, то за такт можно обрабатывать один или часть одного файла), после чего сохраняет текущее состоянее в статических переменных и доджыдается начало следующего такта, что-бы продолжить работу
Re: Exception в другом потоке
От: hmixa  
Дата: 25.08.05 09:06
Оценка:
Хочу такое же — если нашел то напиши в форум.

Есть поток, который иногда затыкается в чужой библиотечной функции. Почему затыкается — второй вопрос. Не хочется просто прибить его. Как бы заставить его выйти из этой функции ?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.