Управление потоком
От: nnnickkk  
Дата: 20.05.09 11:24
Оценка:
Доброго времи суток

Была поставлена задача — управление потоком. То есть, поток запускается, каким-то образом необходимо сообщить ему, чтобы начал работать и после этого чтобы нормально завершился.
Пришел к следующему — управление через events (HANDLE).
В качестве примера — код, в котором инициализируется хук перехвата мыши и клавиатуры и в этом же потоке принимаются сообщения от хука.
Присутствуют HANDLE event[2] — соответственно start/stop.
Log() — вывод лога, в консоль для CLI и в контролс для GUI.

DWORD WINAPI mthread(VOID *lp)
{
        DWORD id = GetCurrentThreadId();

        MSG msg;
        BOOL ret;

        int play = 0;
        int hook = 0;
        
        while(1)
        {
                switch (MsgWaitForMultipleObjects(1,&event[play],FALSE,INFINITE,QS_POSTMESSAGE|QS_ALLINPUT))
                {
                        case WAIT_OBJECT_0:
                                if (!play)
                                {
                                        play = 1;
                                        hook = SetInputHooks(id,1,1);
                                        Log("*-- %ld event - start hook=%d",id,hook);
        
                                        ret = PeekMessage(&msg,NULL,WM_USER,WM_USER+20,PM_NOREMOVE);
                                }
                                else
                                {
                                        Log("--* %ld event - exit",id);
                                        ResetInputHooks(id);                                    
                                        ExitThread(0);
                                }
                                break;
                        case WAIT_OBJECT_0+1:
                                ret = GetMessage(&msg,NULL,WM_USER,WM_USER+100);

                                if (ret)
                                        switch (msg.message)
                                        {
                                                case WM_WORK:
                                                        Log("-*- %ld WM_WORK",id);
                                                        break;
                                                case WM_HOOK_MOUSE:
                                                {
                                                        short x = LOWORD(msg.lParam);
                                                        short y = HIWORD(msg.lParam);

                                                        Log("-*- %ld mouse: %d x=%d y=%d",id,msg.wParam,x,y);
                                                }
                                                break;
                                                case WM_HOOK_KEYBOARD:
                                                break;
                                                
                                        }
                                        
                                break;
                }
        }

        return 0L;
}


Результат:
CLI — всё ОК.
GUI — event на завершение потока не "ловится"

Дополнительно.
Предыдущая версия работала на messages (WM_USER+) с тем же эффектом — с какого-то момента принимались или только внешние сообщения или только сообщения от управляющего потока.

Всё тестировалось в MinGW, VC6, VC8. Результат один (см. выше).

Спасибо.
winapi threads msgwaitformultipleobjects
Re: Управление потоком
От: Андрей Россия  
Дата: 20.05.09 11:42
Оценка:
Здравствуйте, nnnickkk, Вы писали:

skip

я так понимаю, что не отрабатывает ветка:
else
{
  Log("--* %ld event - exit",id);
  ResetInputHooks(id);                                    
  ExitThread(0);
}


так?

а как пытаешься завершить поток?
где код?
Re[2]: Управление потоком
От: nnnickkk  
Дата: 20.05.09 12:07
Оценка:
Здравствуйте, Андрей, Вы писали:

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


А>skip


А>я так понимаю, что не отрабатывает ветка:

А>
А>else
А>{
А>  Log("--* %ld event - exit",id);
А>  ResetInputHooks(id);                                    
А>  ExitThread(0);
А>}
А>


А>так?


А>а как пытаешься завершить поток?

А>где код?

SetEvent(event[1]);
Вот и вся попытка завершить поток.
SetEvent(event[0]) — старт потока, проходит успешно

Инициализация events:
event[0] = CreateEvent(NULL,TRUE,FALSE,NULL);
event[1] = CreateEvent(NULL,TRUE,FALSE,NULL);

Как-то не подумал, что это понадобится. Сорри.
Re[3]: Управление потоком
От: ex-BK  
Дата: 20.05.09 12:12
Оценка:
> switch (MsgWaitForMultipleObjects(1
а если вместо "1", размер массива хендлов задать в первом параметре
Re[4]: Управление потоком
От: nnnickkk  
Дата: 20.05.09 12:19
Оценка:
Здравствуйте, ex-BK, Вы писали:


>> switch (MsgWaitForMultipleObjects(1

EB>а если вместо "1", размер массива хендлов задать в первом параметре

Массив из 2-х event.
После приема 1-го (start) переключается на прием второго.
Парадокс в том, что в CLI ВСЁ работает как надо, затык только в GUI (когда основной поток еще и окно обрабатывает)
Re[5]: Управление потоком
От: dcb-BanDos Россия  
Дата: 20.05.09 12:22
Оценка:
Здравствуйте, nnnickkk, Вы писали:

N>Здравствуйте, ex-BK, Вы писали:



>>> switch (MsgWaitForMultipleObjects(1

EB>>а если вместо "1", размер массива хендлов задать в первом параметре

N>Массив из 2-х event.

N>После приема 1-го (start) переключается на прием второго.
N>Парадокс в том, что в CLI ВСЁ работает как надо, затык только в GUI (когда основной поток еще и окно обрабатывает)

тебе говорят про :


MsgWaitForMultipleObjects


nCount [in]

The number of object handles in the array pointed to by pHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS minus one.


почему у тебя там 1 ?
Ничто не ограничивает полет мысли программиста так, как компилятор.
Re[6]: Управление потоком
От: Аноним  
Дата: 20.05.09 12:42
Оценка:
DB>тебе говорят про :
DB>

DB>MsgWaitForMultipleObjects
DB>nCount [in]
DB> The number of object handles in the array pointed to by pHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS minus one.


DB>почему у тебя там 1 ?

вероятно потому что он ждет одного события
Re[7]: Управление потоком
От: Аноним  
Дата: 20.05.09 12:56
Оценка:
Что-то странно как-то вызывается MsgWaitForMultipleObjects и во втором параметре.
Туда нужно весь массив передавать, а не только первый элемент.
Как-то так:

DWORD hndlCount = 0;
hndlCount = sizeof(event) / sizeof(event[0]); 
MsgWaitForMultipleObjects(hndlCount, event, ...
Re: Управление потоком
От: std.denis Россия  
Дата: 20.05.09 14:04
Оценка:
Тут бы еще пример получаемого лога привести. И доработать журналирование: добавить после MsgWaitForMultipleObjects вывод кода который она выдает. Как минимум будет видно приходит ли сообщение или может оно на полпути заткнулось в GetMessage — ибо у вас нет информации о завершении итерации цикла, при многих вариантах выполнения.
Re[8]: Управление потоком
От: Аноним  
Дата: 20.05.09 14:06
Оценка:
А>Что-то странно как-то вызывается MsgWaitForMultipleObjects и во втором параметре.
А>Туда нужно весь массив передавать, а не только первый элемент.
во первых там не первый элемент указывается а play-ый. Во вторых может ему только один этот ивент и надо ждать. Нету ведь функции MsgWaitForSingleObject
Re: Управление потоком
От: Аноним  
Дата: 20.05.09 14:13
Оценка:
между прочим в консольных приложениях time slice больше в 2 раза чем в гуевых. Потому возможно у вас просто обычный рэйс, который вылазит в гуевых приложениях чаще
Re: Управление потоком
От: std.denis Россия  
Дата: 20.05.09 14:22
Оценка:
Да, забыл спросить — а почему нельзя обойтись только лишь сообщениями без событий? И цикл был бы более удобочитаем — while + GetMessage.
Кстати, есть еще одна интересная фича:

MsgWaitForMultipleObjects does not return if there is unread input of the specified type in the message queue after the thread has called a function to check the queue. This is because functions such as PeekMessage, GetMessage, GetQueueStatus, and WaitMessage check the queue and then change the state information for the queue so that the input is no longer considered new. A subsequent call to MsgWaitForMultipleObjects will not return until new input of the specified type arrives. The existing unread input (received prior to the last time the thread checked the queue) is ignored.

Я это об вызове PeekMessage после SetInputHooks.
Re[3]: Управление потоком
От: Андрей Россия  
Дата: 21.05.09 03:18
Оценка:
Здравствуйте, nnnickkk, Вы писали:

skip

N>SetEvent(event[1]);

N>Вот и вся попытка завершить поток.

и что после этого делаешь?
сразу приложение завершаешь или что-то другое?

похоже, что у тебя просто-напросто гонки потоков
правильней надо как-то так делать:

  SetEvent(event[1]);
  WaitForSingleObject(threadID);

  // вот здесь поток уже точно завершился (ну или все зависло на предыдущем вызове ;) )
Re[2]: Управление потоком
От: Аноним  
Дата: 21.05.09 12:09
Оценка:
Здравствуйте, std.denis, Вы писали:

SD>Да, забыл спросить — а почему нельзя обойтись только лишь сообщениями без событий? И цикл был бы более удобочитаем — while + GetMessage.

SD>Кстати, есть еще одна интересная фича:
SD>

MsgWaitForMultipleObjects does not return if there is unread input of the specified type in the message queue after the thread has called a function to check the queue. This is because functions such as PeekMessage, GetMessage, GetQueueStatus, and WaitMessage check the queue and then change the state information for the queue so that the input is no longer considered new. A subsequent call to MsgWaitForMultipleObjects will not return until new input of the specified type arrives. The existing unread input (received prior to the last time the thread checked the queue) is ignored.

SD>Я это об вызове PeekMessage после SetInputHooks.

В сообщениях к сожалению тоже происходит затык после передачи сообщений в поток извне (из другого приложения, хука и т.д.)
PeekMessage после SetInputHooks всего лишь создание очереди сообщений (выборка сообщения без удаления)
Re[9]: Управление потоком
От: nnnickkk  
Дата: 21.05.09 12:12
Оценка:
Здравствуйте, Аноним, Вы писали:

А>>Что-то странно как-то вызывается MsgWaitForMultipleObjects и во втором параметре.

А>>Туда нужно весь массив передавать, а не только первый элемент.
А>во первых там не первый элемент указывается а play-ый. Во вторых может ему только один этот ивент и надо ждать. Нету ведь функции MsgWaitForSingleObject

Всё верно.
Как я уже писал интересует, то что второе сообщение (play=1) не принимается
Re[10]: Управление потоком
От: rastoman  
Дата: 22.05.09 06:30
Оценка:
Здравствуйте, nnnickkk, Вы писали:

N>Всё верно.

N>Как я уже писал интересует, то что второе сообщение (play=1) не принимается

Я видимо плохо знаю MsgWaitForMultipleObjects. Точнее вообще не работал с ней
В каком случае в конкретном коде управление перейдёт в эту ветку:?
case WAIT_OBJECT_0+1:

Дело в том, что пр использовании WaitForMultipleObjects переход "WAIT_OBJECT_0+1" означал бы, что сработал второй ивент в массиве. А, т.к. в массиве всего один ивент, управление в данную ветку приходить не должно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[11]: Управление потоком
От: Андрей Россия  
Дата: 22.05.09 06:46
Оценка:
Здравствуйте, rastoman, Вы писали:

skip

в случае с MsgWaitXXX управление в эту ветку придет при появлении сообщений в очереди
так что в эту ветку управление таки приходить должно
Re[10]: Управление потоком
От: Андрей Россия  
Дата: 22.05.09 06:58
Оценка:
Здравствуйте, nnnickkk, Вы писали:

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


А>>>Что-то странно как-то вызывается MsgWaitForMultipleObjects и во втором параметре.

А>>>Туда нужно весь массив передавать, а не только первый элемент.
А>>во первых там не первый элемент указывается а play-ый. Во вторых может ему только один этот ивент и надо ждать. Нету ведь функции MsgWaitForSingleObject

N>Всё верно.

N>Как я уже писал интересует, то что второе сообщение (play=1) не принимается

ты так и не ответил на вопросы отсюда
Автор: Андрей
Дата: 21.05.09

может, ты просто не даешь шанса потоку отработать это событие?

такое запросто может быть, если приоритет основного потока выше, чем рабочего
ты выставил событие и тут же завершил программу или убил поток
Re[12]: Управление потоком
От: rastoman  
Дата: 22.05.09 06:59
Оценка:
А>в случае с MsgWaitXXX управление в эту ветку придет при появлении сообщений в очереди
А>так что в эту ветку управление таки приходить должно

В таком случае у меня только одно предположение:
Поток подвисает на GetMessage — можно попробовать вместо неё использовать PeekMessage.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[3]: Управление потоком
От: std.denis Россия  
Дата: 22.05.09 07:46
Оценка:
а как на счет дополнения лога еще несколькими точками, как я писал в соседней ветке
Автор: std.denis
Дата: 20.05.09
?
просто жутко интересно стало в чем же проблема
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.