Опять про потоки.
От: Tarantul Украина  
Дата: 23.11.03 13:05
Оценка:
Эта тема, судя по поиску, много раз обсуждаласт но для себя я решения не нашел

Вопрос: Как можно главному потоку узнать что рабочий поток завершился? При использовании всяких интересных функций вроде WaitForSingleObject(...), Sleep(...) и подобных в _главном_потоке_ всё замирает: главный поток ожидает события (которое должно оповестить о завершении рабочего потока), а рабочий поток не может установить это событие как раз по причине того, что главный поток весь в ожидании

Убивать поток функцией TerminateThread(...) никак нельзя — будет утечка памяти (в моем случае).
Re: Опять про потоки.
От: vadim77 Израиль  
Дата: 23.11.03 13:19
Оценка: 2 (1)
Здравствуйте, Tarantul, Вы писали:

T>Эта тема, судя по поиску, много раз обсуждаласт но для себя я решения не нашел


T>Вопрос: Как можно главному потоку узнать что рабочий поток завершился? При использовании всяких интересных функций вроде WaitForSingleObject(...), Sleep(...) и подобных в _главном_потоке_ всё замирает: главный поток ожидает события (которое должно оповестить о завершении рабочего потока), а рабочий поток не может установить это событие как раз по причине того, что главный поток весь в ожидании


T>Убивать поток функцией TerminateThread(...) никак нельзя — будет утечка памяти (в моем случае).


Try MsgWaitForMultipleObjectsEx

This is code snippet from the book "MS Press — Programming Applications for MS Windows 4th Edition" by Jeffry Richter

BOOL fQuit FALSE; //Should the loop terminate?

while (!fQuit)
{

//Wake when the kernel object is signaled OR
//if we have to process a UI message.
DWORD dwResult = MsgWaitForMultipleObjectsEx(1, &hYourThreadHandle,
INFINITE, QS_ALLEVENTS, MWMO_INPUTAVAILABLE);

switch(dwResult)
{
case WAIT_OBJECT_0: // The event became signaled.
break;

case WAIT_OBJECT_0 + 1: //A message is in our queue.

//Dispatch all of the messages.
MSG msg;
while(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
{
if(msg.message==WM_QUIT)
{
//A WM_QUIT message, exit the loop
fQuit = TRUE;
}
else
{
//Translete and dispatch the message.
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}// Our queue is empty.
break;
}
}//End of while loop
Re: Опять про потоки.
От: Cadet  
Дата: 23.11.03 13:29
Оценка:
Здравствуйте, Tarantul, Вы писали:

T>Эта тема, судя по поиску, много раз обсуждаласт но для себя я решения не нашел


T>Вопрос: Как можно главному потоку узнать что рабочий поток завершился? При использовании всяких интересных функций вроде WaitForSingleObject(...), Sleep(...) и подобных в _главном_потоке_ всё замирает: главный поток ожидает события (которое должно оповестить о завершении рабочего потока), а рабочий поток не может установить это событие как раз по причине того, что главный поток весь в ожидании


То есть как это не может? Рабочий поток не может вызвать SetEvent? Или не происходит выхода из функции
WaitForSingleObject(hWorkingThread/Event, ...)?
Можно конечно не использовать разные Wait... Sleep, а просто непосредственно перед выходом из рабочего потока запостить пользовательское сообщение главному потоку.
... << RSDN@Home 1.1.0 stable >>
Re: Опять про потоки.
От: Андрей 2003  
Дата: 23.11.03 13:35
Оценка:
Здравствуйте, Tarantul, Вы писали:

T>Вопрос: Как можно главному потоку узнать что рабочий поток завершился?


GetExitCodeThread
Re[2]: Опять про потоки.
От: Tarantul Украина  
Дата: 23.11.03 14:10
Оценка:
Здравствуйте, Cadet, Вы писали:

C>Здравствуйте, Tarantul, Вы писали:


T>>Эта тема, судя по поиску, много раз обсуждаласт но для себя я решения не нашел


T>>Вопрос: Как можно главному потоку узнать что рабочий поток завершился? При использовании всяких интересных функций вроде WaitForSingleObject(...), Sleep(...) и подобных в _главном_потоке_ всё замирает: главный поток ожидает события (которое должно оповестить о завершении рабочего потока), а рабочий поток не может установить это событие как раз по причине того, что главный поток весь в ожидании


C>То есть как это не может? Рабочий поток не может вызвать SetEvent? Или не происходит выхода из функции

C>WaitForSingleObject(hWorkingThread/Event, ...)?
C>Можно конечно не использовать разные Wait... Sleep, а просто непосредственно перед выходом из рабочего потока запостить пользовательское сообщение главному потоку.

1) Есть рабочий поток.
2) Есть класс функции которого используются в рабочем потоке, назовем его CWork.
3) Есть другой класс который служит для того чтобы узнать текущее состояние потока, назовем его CWorkState.
4) Классу CWork принадлежит один объект класса CWorkState.
5) Когда нужно принудительно завершить поток вызываем work.workstate.exit(...) — эта функция устанавливает некоторую переменную в true, которая проверяется в потоке, если true, то корректно завершаем поток (не важно как )
6) Перед самым запуском потока вызываем work.workstate.threadstarts(...), где событие устанавливается в nonsignaled state.
7) В конце потока вызываем work.workstate.threadends(...), где событие устанавливается в signaled state.
8) см. п. 5 после вызова exit(...) вызываем work.workstate.wait(...), где вызывается функция WaitForSingleObject(...) для события указанного в п.6 и п.7. Т.к. событие еще не в свободном состоянии (не signaled), то основной поток ждет и тем самым _замараживает_ рабочий поток В итоге получается какое-то взаимное блокирование.

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

P.S. Вообще, интересно если я усыпляю основной поток например при помощи Sleep(...), то у меня что рабочие потоки тоже должны спать? У меня спят.
Re[3]: Опять про потоки.
От: Аноним  
Дата: 23.11.03 15:35
Оценка:
Здравствуйте, Tarantul, Вы писали:

T>Здравствуйте, Cadet, Вы писали:


C>>Здравствуйте, Tarantul, Вы писали:


T>>>Эта тема, судя по поиску, много раз обсуждаласт но для себя я решения не нашел


T>>>Вопрос: Как можно главному потоку узнать что рабочий поток завершился? При использовании всяких интересных функций вроде WaitForSingleObject(...), Sleep(...) и подобных в _главном_потоке_ всё замирает: главный поток ожидает события (которое должно оповестить о завершении рабочего потока), а рабочий поток не может установить это событие как раз по причине того, что главный поток весь в ожидании


C>>То есть как это не может? Рабочий поток не может вызвать SetEvent? Или не происходит выхода из функции

C>>WaitForSingleObject(hWorkingThread/Event, ...)?
C>>Можно конечно не использовать разные Wait... Sleep, а просто непосредственно перед выходом из рабочего потока запостить пользовательское сообщение главному потоку.

T>1) Есть рабочий поток.

T>2) Есть класс функции которого используются в рабочем потоке, назовем его CWork.
T>3) Есть другой класс который служит для того чтобы узнать текущее состояние потока, назовем его CWorkState.
T>4) Классу CWork принадлежит один объект класса CWorkState.
T>5) Когда нужно принудительно завершить поток вызываем work.workstate.exit(...) — эта функция устанавливает некоторую переменную в true, которая проверяется в потоке, если true, то корректно завершаем поток (не важно как )
T>6) Перед самым запуском потока вызываем work.workstate.threadstarts(...), где событие устанавливается в nonsignaled state.
T>7) В конце потока вызываем work.workstate.threadends(...), где событие устанавливается в signaled state.
T>8) см. п. 5 после вызова exit(...) вызываем work.workstate.wait(...), где вызывается функция WaitForSingleObject(...) для события указанного в п.6 и п.7. Т.к. событие еще не в свободном состоянии (не signaled), то основной поток ждет и тем самым _замараживает_ рабочий поток В итоге получается какое-то взаимное блокирование.

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


T>P.S. Вообще, интересно если я усыпляю основной поток например при помощи Sleep(...), то у меня что рабочие потоки тоже должны спать? У меня спят.


Почему ты не хочешь использовать MsgWait... то о чем я писал в первом ответе. Она как раз и предназначаена для таких случаев т.е. ждет события (выход из потока, event и т.д.) а так же пропускает все сообщения Windows. Проблема только в том что пришедшее сообщение нужно корректно обработать. У меня несколько раз возникала подобная ситуация и пользовался именно таким способом. ВСе прекрасно отрабатывало.
Re[3]: Опять про потоки.
От: Cadet  
Дата: 23.11.03 15:36
Оценка:
Здравствуйте, Tarantul, Вы писали:

Так, еще раз, и по порядку.

T>5) Когда нужно принудительно завершить поток вызываем work.workstate.exit(...) — эта функция устанавливает некоторую переменную в true...


Эта функция после установки переменной сразу возвращает управление?

T>6) Перед самым запуском потока вызываем work.workstate.threadstarts(...), где событие устанавливается в nonsignaled state.

T>7) В конце потока вызываем work.workstate.threadends(...), где событие устанавливается в signaled state.

Зачем заморачиваться с событием, когда можно ждать WaitForSingleObject(hWorkThread, INFINITE)?

T>8) см. п. 5 после вызова exit(...) вызываем work.workstate.wait(...), где вызывается функция WaitForSingleObject(...) для события указанного в п.6 и п.7. Т.к. событие еще не в свободном состоянии (не signaled), то основной поток ждет и тем самым _замараживает_ рабочий поток В итоге получается какое-то взаимное блокирование.


Вот код, как я его понял. Все работает.
#include <windows.h>

class Test
{
    BOOL m_bExit;

public:
    Test() { m_bExit = FALSE; }
    
    ~Test() {}
    
    BOOL GetExitState() const { return m_bExit; }
    void Exit() { m_bExit = TRUE; };
    
    void Wait(HANDLE handle) const
    {
        WaitForSingleObject(handle, INFINITE);
    }

    // Имитируем большую работу
    void Work() const { Sleep(5000); }
};

Test test;

// Для определения наличия потока
HANDLE hEvtOnline;


DWORD WINAPI Thread(PVOID pvParam)
{
    // Теперь поток есть
    SetEvent(hEvtOnline);

    while(!test.GetExitState())
        test.Work();

    return 0;
}


int WINAPI WinMain(HINSTANCE hInstance, 
                   HINSTANCE hPrevInstance, 
                   LPSTR     lpCmdLine, 
                   int         nShowCmd)
{
    hEvtOnline = CreateEvent(0, TRUE, FALSE, 0);
    HANDLE hThread = CreateThread(0, 0, Thread, 0, 0, 0);

    // Удостоверимся, что поток есть
    WaitForSingleObject(hEvtOnline, INFINITE);

    CloseHandle(hEvtOnline);

    MessageBox(NULL, "Press OK then exit", "", MB_OK);

    test.Exit();
    test.Wait(hThread);

    MessageBox(NULL, "Exit!", "Info", MB_OK);

    CloseHandle(hThread);
        
    return 0;
}
... << RSDN@Home 1.1.0 stable >>
Re[2]: Опять про потоки.
От: Tarantul Украина  
Дата: 23.11.03 19:54
Оценка:
Здравствуйте, vadim77, Вы писали:

V>Try MsgWaitForMultipleObjectsEx


V>This is code snippet from the book "MS Press — Programming Applications for MS Windows 4th Edition" by Jeffry Richter


V>BOOL fQuit FALSE; //Should the loop terminate?


V>while (!fQuit)

V>{

V>//Wake when the kernel object is signaled OR

V>//if we have to process a UI message.
V> DWORD dwResult = MsgWaitForMultipleObjectsEx(1, &hYourThreadHandle,
V> INFINITE, QS_ALLEVENTS, MWMO_INPUTAVAILABLE);

V> switch(dwResult)

V> {
V> case WAIT_OBJECT_0: // The event became signaled.
V> break;

V> case WAIT_OBJECT_0 + 1: //A message is in our queue.


V> //Dispatch all of the messages.

V> MSG msg;
V> while(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
V> {
V> if(msg.message==WM_QUIT)
V> {
V> //A WM_QUIT message, exit the loop
V> fQuit = TRUE;
V> }
V> else
V> {
V> //Translete and dispatch the message.
V> TranslateMessage(&msg);
V> DispatchMessage(&msg);
V> }
V> }// Our queue is empty.
V> break;
V> }
V>}//End of while loop

Если MsgWait... действительно пропускает виндовс-сообщения, то это как раз то, что надо.
На данный момент в главном потоке я остановился на таком _рабочем_ варианте:
void CMainFrame::OnCmdStopScan()
{
    if(pScanThread!=NULL)    
    {
        m_pReportDlg->m_pPS->m_SearchPP.m_ScanLocker.ExitFromThread();

        bool fWaiting=true;
        while(fWaiting)
        {
            if(WaitForSingleObject(pScanThread->m_hThread,0)==WAIT_TIMEOUT)
            {
                MSG msg;
                if(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }
            else fWaiting=false;
        }
    }
}

Всем спасибо.
Re[3]: Опять про потоки.
От: Аноним  
Дата: 23.11.03 22:15
Оценка:
Здравствуйте, Tarantul, Вы писали:

T>Здравствуйте, vadim77, Вы писали:


V>>Try MsgWaitForMultipleObjectsEx


V>>This is code snippet from the book "MS Press — Programming Applications for MS Windows 4th Edition" by Jeffry Richter


V>>BOOL fQuit FALSE; //Should the loop terminate?


V>>while (!fQuit)

V>>{

V>>//Wake when the kernel object is signaled OR

V>>//if we have to process a UI message.
V>> DWORD dwResult = MsgWaitForMultipleObjectsEx(1, &hYourThreadHandle,
V>> INFINITE, QS_ALLEVENTS, MWMO_INPUTAVAILABLE);

V>> switch(dwResult)

V>> {
V>> case WAIT_OBJECT_0: // The event became signaled.
V>> break;

V>> case WAIT_OBJECT_0 + 1: //A message is in our queue.


V>> //Dispatch all of the messages.

V>> MSG msg;
V>> while(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
V>> {
V>> if(msg.message==WM_QUIT)
V>> {
V>> //A WM_QUIT message, exit the loop
V>> fQuit = TRUE;
V>> }
V>> else
V>> {
V>> //Translete and dispatch the message.
V>> TranslateMessage(&msg);
V>> DispatchMessage(&msg);
V>> }
V>> }// Our queue is empty.
V>> break;
V>> }
V>>}//End of while loop

T>Если MsgWait... действительно пропускает виндовс-сообщения, то это как раз то, что надо.

T>На данный момент в главном потоке я остановился на таком _рабочем_ варианте:
T>
T>void CMainFrame::OnCmdStopScan()
T>{
T>    if(pScanThread!=NULL)    
T>    {
T>        m_pReportDlg->m_pPS->m_SearchPP.m_ScanLocker.ExitFromThread();

T>        bool fWaiting=true;
T>        while(fWaiting)
T>        {
T>            if(WaitForSingleObject(pScanThread->m_hThread,0)==WAIT_TIMEOUT)
T>            {
T>                MSG msg;
T>                if(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
T>                {
T>                    TranslateMessage(&msg);
T>                    DispatchMessage(&msg);
T>                }
T>            }
T>            else fWaiting=false;
T>        }
T>    }
T>}
T>

T>Всем спасибо.


????
Да но у тебя не MsgWait... а WaitForSingle... я не проверял но такая штука не должна работать корректно. Я имею ввиду что с timeout 0 ты попадаешь в бесконечный цикл вплоть до выхода из фонового потока т.е. есть сообщение — обрабатываешь его нет — проверяешь по новой. На мой взгляд недстаток в том что такой цикл по идее должен загрузить на все 100% процессор. Все равно что поставить

for (int i = 0; i < 1000000000; i++);

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

vadik77
Re[4]: Опять про потоки.
От: Tarantul Украина  
Дата: 24.11.03 04:38
Оценка:
Здравствуйте, Аноним, Вы писали:

А>????

А>Да но у тебя не MsgWait... а WaitForSingle... я не проверял но такая штука не должна работать корректно. Я имею ввиду что с timeout 0 ты попадаешь в бесконечный цикл вплоть до выхода из фонового потока т.е. есть сообщение — обрабатываешь его нет — проверяешь по новой. На мой взгляд недстаток в том что такой цикл по идее должен загрузить на все 100% процессор. Все равно что поставить

А> for (int i = 0; i < 1000000000; i++);


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


А>vadik77


Именно WaitForSingle..., причем в этом "бесконечном" цикле есть выборка сообщений, так что процессор вроде на 100% не грузиться и работает все нормально.
Re[5]: Опять про потоки.
От: vadim77 Израиль  
Дата: 24.11.03 11:18
Оценка:
Здравствуйте, Tarantul, Вы писали:

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


А>>????

А>>Да но у тебя не MsgWait... а WaitForSingle... я не проверял но такая штука не должна работать корректно. Я имею ввиду что с timeout 0 ты попадаешь в бесконечный цикл вплоть до выхода из фонового потока т.е. есть сообщение — обрабатываешь его нет — проверяешь по новой. На мой взгляд недстаток в том что такой цикл по идее должен загрузить на все 100% процессор. Все равно что поставить

А>> for (int i = 0; i < 1000000000; i++);


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


А>>vadik77


T>Именно WaitForSingle..., причем в этом "бесконечном" цикле есть выборка сообщений, так что процессор вроде на 100% не грузиться и работает все нормально.



#include "stdafx.h"
#include <stdlib.h>
#include <iostream.h>
#include <windows.h>


DWORD threadFunc(LPVOID lpParam)
{
    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    DWORD dwThread = 0;
    HANDLE m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadFunc, NULL, 
        CREATE_SUSPENDED, &dwThread);

    if (m_hThread)
    {
        bool fWaiting=true;
        while(fWaiting)
        {
            if(WaitForSingleObject(m_hThread,0)==WAIT_TIMEOUT)
            {
                MSG msg;
                if(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }
            else fWaiting=false;
        }
    }

    int c;
    cin >> c;

    return 0;

}; // main


zagruzka processora 100%...
Re: Опять про потоки.
От: Аноним  
Дата: 24.11.03 14:43
Оценка:
Здравствуйте, Tarantul, Вы писали:

T>Эта тема, судя по поиску, много раз обсуждаласт но для себя я решения не нашел


T>Вопрос: Как можно главному потоку узнать что рабочий поток завершился? При использовании всяких интересных функций вроде WaitForSingleObject(...), Sleep(...) и подобных в _главном_потоке_ всё замирает: главный поток ожидает события (которое должно оповестить о завершении рабочего потока), а рабочий поток не может установить это событие как раз по причине того, что главный поток весь в ожидании


T>Убивать поток функцией TerminateThread(...) никак нельзя — будет утечка памяти (в моем случае).


ThreadDone = true; //приказываем потоку завершиться
do
{
Code = ResumeThread(hThread);
}
while ((Code > 1) && (Code != 0xFFFFFFFF)); //Запускаем поток, если он остановлен
do
{
GetExitCodeThread(hThread,&Code); //
}
while (Code == STILL_ACTIVE); //STILL_ACTIVE — поток НЕ завершен, иначе — завершен
CloseHandle(hThread);
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.