Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > зависает окно при обработке


Автор: mrgloom 29.6.2012, 10:20
есть окно, на нём кнопка, на кнопке обработчик, в обработчике некоторая полезная работа которая требует времени.
точнее там 2 кнопки старт и стоп, хотелось бы чтобы по кнопке стоп можно было остановить процесс, т.е. вообще его прервать(т.е. все данные чтобы остановились на предыдущем шаге) или же хотя бы дождаться завершения текущего шага зафиксировать переменные и остановится.

Код

void CControlDlg::OnStart()
{
    is_not_stop=true;
    //имитация деятельности
    //Sleep(6000); 
    for(int64 j=0;j<10;++j)
        for(int64 i=0;i<1000000;++i)
   {
      if(is_not_stop)
         {
            int64 f= (double)i*cos((double)i)*sin((double)i);
            updateinfo();
         }
      else
           break;
   }
}
void CControlDlg::OnStop()
{
is_not_stop=false;
}


но проблема в том, что во время процедуры окно почему то замирает и даже кнопк астоп не нажимается не говоря уже о обновлении информации в окне.

Автор: vol4ek 29.6.2012, 16:54
Код


static UINT Function(LPVOID param)
{
    // Здесь Ваш код

    return 0;
}

void CControlDlg::OnStart()
{
    AfxBeginThread(Function,this,0,0,THREAD_PRIORITY_IDLE ); 
}



Почитайте про потоки. smile 

Автор: Earnest 2.7.2012, 08:56
Потоки, да, но тогда не получится
Цитата

хотелось бы чтобы по кнопке стоп можно было остановить процесс, т.е. вообще его прервать(т.е. все данные чтобы остановились на предыдущем шаге) или же хотя бы дождаться завершения текущего шага зафиксировать переменные и остановится

т.к. поток прерывается в любой момент. Ну то есть можно, но с доп. геморроем.

В твоей ситуации лучше разбить задачу на шаги - она и так у тебя разбита, как я понимаю. Каждый шаг оформить как ф-ю какого-то класса, который будет хранить все состояние процесса (те самые переменные, которые ты хочешь зафиксировать), а дальше 2 варианта:
1) цикл, управляемый PickMessage-DispatchMessage с проверкой не пора ли остановиться после каждого шага. В принципе, здесь не обязательно выделять шаг в отдельную функцию, но сложнее добиться полной прозрачности цикла для действий пользователя
2) выполнять каждый шаг по какому-то сообщению, которое самому- же себе и посылать - асинхронно, конечно. Т.е. крутится обычный стандартный цикл обработки сообщений, который кнопки обрабатывает и т.д. Чтобы запустить рабочий процесс (по нажатию кнопки старт), посылаешь сообщение, по получении которого выполняешь один шаг и тут же посылаешь новое сообщение. По нажатию кнопки стоп просто ставим флаг bStop, например. А обработчик нашего шагового сообщения сначала проверяет флаг, а уже потом выполняет свою работу. Или не выполняет. Как-то так.

Автор: mrgloom 2.7.2012, 11:39
попробовал с циклом всё ок.
но у меня не цикл, а некоторые действия(захват кадров) которые требуют некоторого времени.
точнее у меня получается тоже цикл, только минимальные действие занимает несколько большее время, чем в цикле в примере.

Код

BOOL CControlDlg::PumpMessage(void)
{
   CWinThread *pThread = AfxGetThread();
   MSG msg;
   while(::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
   {
       if (!pThread->PumpMessage()) 
           break; 
   }
   if(m_Session.State == PAUSED)
     return FALSE;
   return TRUE;
};



                    
Код

Sleep(6000); // имитация захвата кадра, трубется некоторое время
                    //for(int64 j=0;j<10;++j)
                    //for(int64 i=0;i<1000000;++i)
                    //{
                    //    if(PumpMessage()==TRUE)
                    //        int64 f= (double)i*cos((double)i)*sin((double)i);
                    //    else
                    //    {
                    //        //записываем тут текущее положение и выходим
                    //        return;
                    //    }
                    //}    

                    if(PumpMessage()==TRUE)
                    {
                    }
                    else
                    {
                        //записываем тут текущее положение и выходим
                        return;
                    }


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

Автор: mrgloom 2.7.2012, 13:10
решил вроде проблему так,

Код

UINT CControlDlg::thread_func(LPVOID param)
{
    INFO*  pSession= (INFO*)param;
    for(int r=0;r<pSession->NumRows;++r)
    {
        for(int c=0;c<pSession->NumCols;++c)
        {
            if(pSession->State == PAUSED)
            {
                //должны записать текущую позицию
                return 0;
            }
            Sleep(6000);
        }
    }
    return 0;
};


Код

void CControlDlg::OnStart()
{
CWinThread* myWinThread= AfxBeginThread(CControlDlg::thread_func,(LPVOID)&m_Session);
}


но проблема в том что когда нажимаешь стоп на форме, то состояние на форме сразу меняется, и не ждет окончания треда, а надо бы всё заморозить и дождаться окончания треда.
или надо в на кнопку стоп повесить еще WaitForSingleObject ?

Добавлено @ 13:16
но тогда непонятно почему строчка WaitForSingleObject выполняется и проходит сквозь неё, а только после этого выполняется возврат из треда?  т.е. мне нужно чтобы мы подождали пока тред закончит итерацию и  не делали до этого UpdateControl.

Код

void CControlDlg::OnPauseScan()
{

        m_Session.State = PAUSED;

        WaitForSingleObject(myWinThread,MAX_TIME_TO_WAIT_THREAD); //почему не ждем?

        UpdateControls();
}

Автор: mrgloom 2.7.2012, 15:24
ну вообщем вопрос я решил путем добавления глобальной булевой переменной, и тред когда завершается проставляем этот флаг.
а на обработчике кнопки стоп я добавил 
Цитата

while(!m_is_thread_finish)
  {
    Sleep(100);
  }

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

Автор: mrgloom 5.7.2012, 16:41
не могу понять как работает WaitForSingleObject.

Код

void CControlDlg::OnStart()
{
    //m_WorkWinThread определён в  CControlDlg
    m_WorkWinThread= AfxBeginThread(CControlDlg::GetFrame,this);
}

Код

void CControlDlg::OnPause()
{
    global_flag=true;
    ::WaitForSingleObject(m_WorkWinThread->m_hThread, INFINITE);//ну и тут не может дождаться завершения треда
    //причем непонятно работает ли при это сам тред, такое ощущение что нет
}


Код

CControlDlg::GetFrame()
{
   for..
   for..
    if(global_flag==true) //т.е. сюда почему то не доходит, а всё виснет похоже на WaitForSingleObject
      {
         return 0;
      }    
}


а если WaitForSingleObject убрать то доходит до строчки  
Цитата

if(global_flag==true)

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

Автор: mrgloom 6.7.2012, 14:48
http://forums.codeguru.com/showthread.php?305166-Windows-SDK-Thread-How-to-end-a-thread

делал всё как тут, всё равно не хочет заходить в условие 
Код

if(::WaitForSingleObject(pthis->m_StopThread, 0) == WAIT_OBJECT_0)


а виснет на

Код

// Wait until thread finished
::WaitForSingleObject(m_WaitThread, INFINITE); 

Автор: Dem_max 6.7.2012, 16:07
INFINITE говорит что ожидать события бесконечно пока поток не завершится

Добавлено через 1 минуту и 23 секунды
WaitForSingleObject(myWinThread,MAX_TIME_TO_WAIT_THREAD); //почему не ждем?
ждет на время  MAX_TIME_TO_WAIT_THREAD при условии что поток не завершен и myWinThread валиден.

Автор: mrgloom 9.7.2012, 09:15
Цитата(Dem_max @  6.7.2012,  16:07 Найти цитируемый пост)
INFINITE говорит что ожидать события бесконечно пока поток не завершится

Добавлено через 1 минуту и 23 секунды
WaitForSingleObject(myWinThread,MAX_TIME_TO_WAIT_THREAD); //почему не ждем?
ждет на время  MAX_TIME_TO_WAIT_THREAD при условии что поток не завершен и myWinThread валиден. 



да, это то я понял, мне и нужно пока поток не завершится,  но такое ощущение, что происходит дедлок прям на WaitForSingleObject, только почему не ясно.

Добавлено @ 09:30
т.е. еще раз повторюсь такое ощущение, что при WaitForSingleObject всё замирает на нём и в треде ничего не выполняется, если же убрать 
Код

::WaitForSingleObject(m_WaitThread, INFINITE);
, а просто оставить 
Код

::SetEvent(m_StopThread);
 
то в ветку  в треде заходит, но дело, то в том, что надо подождать пока он завершится в основном потоке ,а этого сделать не получается.
Код

            if(::WaitForSingleObject(pthis->m_StopThread, 0) == WAIT_OBJECT_0)
            {

                // Set event
                ::SetEvent(pthis->m_WaitThread);

                LogMsg(_T("return from thread \r\n"));
                return 0;
            }

Автор: mrgloom 9.7.2012, 11:33

попробовал так же 

Код

while(::WaitForSingleObject(m_WaitThread, 0)!= WAIT_OBJECT_0)
            Sleep(1000);


так же на брекпоинт в треде не заходит, причем ни на какой.

Автор: mrgloom 10.7.2012, 12:04
всё таки я не понял как работать с этим кодом для прерывания

http://www.tenouk.com/visualcplusmfc/visualcplusmfc22.html
Код

MSG message;
if (::PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
{
    ::TranslateMessage(&message);
    ::DispatchMessage(&message);
}

Автор: Dem_max 12.7.2012, 06:33
Не париться, вынести все вычисления в поток и окно не будет зависать.
Все легко и просто.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)