Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Ожидание завершения множества потоков  (Прочитано 20764 раз)
0 Пользователей и 1 Гость смотрят эту тему.
asker
Помогающий

ru
Offline Offline
Пол: Мужской

« : 04-10-2006 02:25 » 

Пишу в VC++ 2003 (MFC)

У меня есть класс потока CMyThread - созданный Wizard'om

Код:
class CMyTread : public CWinThread
{
...
virtual BOOL InitInstance()
{
...
}

...
};

В основной проге создаю n потоков этого класса.

// Указатель на массив дескрипторов потоков
HANDLE* pHandleThreads = new HANDLE[n];

...

for(i = 0, j = 0; pCurList != NULL; pCurList = pCurList->m_pNext, i++) {
for(pCurList1 = pHeadList; pCurList1 != NULL; pCurList1 = pCurList1->m_pNext, j++) {
               // этот блок взят из примера mtgdi
pThread = new CMyTread(i, j, pCurList, pCurList1);
ASSERT_VALID(pThread);
pThread->m_pThreadParams = NULL;
// Create Thread in a suspended state so we can set the Priority
// before it starts getting away from us
if (!pThread->CreateThread(CREATE_SUSPENDED)) {
delete pThread;
_tprintf(_T("System Error: Thread not created\n"));
return 1;
}
// since everything is successful, add the thread to our array
pHandleThreads[j] = *pThread;
TRACE("j = %d\t%p\n", j, pHandleThreads[j]);
// If you want to make the sample more sprightly, set the thread priority here
// a little higher. It has been set at idle priority to keep from bogging down
// other apps that may also be running.
VERIFY(pThread->SetThreadPriority(THREAD_PRIORITY_NORMAL));
// Now the thread can run wild
pThread->ResumeThread();
}
}

// потоки выполняют нужные действия и т.д.

Код:
// Ждем пока все потоки закончат работу
WaitForMultipleObjects(nCount * nCount * 9, pHandleThreads, TRUE, INFINITE);    // ??? не работает!
// Пробовал еще так:
/*
for(i = 0; i < nCount * nCount * 9; i++) {
WaitForSingleObject(pHandleThreads[i], INFINITE);
}
*/

Все это виснет, хотя если посмотреть завершается ли InitInstance, то ответ да.

И еще это дело не всегда не работает, бывает что работает.

Я наверное чего-то не знаю или не понимаю, подсажите пожалуйста
« Последнее редактирование: 13-12-2007 20:14 от Алексей1153++ » Записан

С уважением, asker
asker
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 04-10-2006 02:36 » 

P.S.: еще попутно вопрос: Как получить указатель на объект потока зная его хендл
Записан

С уважением, asker
sss
Специалист

ru
Offline Offline

« Ответ #2 : 04-10-2006 03:25 » 

Код:
WaitForMultipleObjects(nCount * nCount * 9,

 ... nCount * nCount * 9 = ? ( <= MAXIMUM_WAIT_OBJECTS ?)
« Последнее редактирование: 04-10-2006 03:28 от sss » Записан

while (8==8)
Serg79
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 04-10-2006 04:39 » 

asker ты зря грешиш на функцию WaitForSingleObject. Проверь правельность формирования передоваемого ей массива HANDLE-в. Попробуй ждать не INFINITE а конечное время и посмотри что возвратит функция WaitForSingleObject так же вызови после этого GetLastError и посмотри что она возвратит. Попробу ждать не все объекты а только один (третий параметр функции WaitForSingleObject). Короче, заставь функцию WaitForSingleObject возвратить управление и посмотри что она возвращает. Может твои созданные потоки зацикливаются или как-то блокируют друг друга.

А лучше попробуй сначало создавать потоки без использования средств MFC с использованием только WinAPI (CreateThread) чтобы разобраться для себя как это все работает.
Записан
asker
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 08-10-2006 12:53 » 

sss nCount * nCount * 9 == n
На счет MAXIMUM_WAIT_OBJECTS проверки у меня не стоит.
Но подозреваю что меньше, хотя ... (MAXIMUM_WAIT_OBJECTS > 1000?)
Serg79:
1) я не гришу на WaitForSingleObject или WaitForMultipleObjects, ни в коем случае (хотя бывает и такое)
2) Что значит "Проверь правельность формирования передоваемого ей массива HANDLE-в"?
3) Насчет изменения INFINITE на TIMEOUT, пробовал, но не смотрел че возвращает (мой недочет, каюсь) (попробую попозже и сообщу)
4)
Попробу ждать не все объекты а только один (третий параметр функции WaitForSingleObject).
Пробовал на первом и виснет, я для этого и пробовал перейти на WFSO
5) Потоки действительно зависят друг от друга, но косвенно и они не блокируют друг друга я проверял. Зацикливаться они не могут, т.к. там нет цикла.

Насчет перехода на АПИ попробую.

А теперь от себя:
Фишка в том, что она практически всегда работает, за исключением 3 случаев (из 15 проверянных - дальше >1500 потоков):
Справка: У меня такая зависимость. Создается n вершин в дереве => n*3 элементов списка => n*n*9 потоков. Ограничение на n <= 12
Так вот когда n=1 || 2 вообще виснет, когда 8 - иногда да, иногда нет
для остальных n - ok.

Посмотрю че возвращает WFSO || WFMO и сообщю.

P.S.: я делаю очень неправильную вещь: закрываю хендл потока внутри InitInstance потока, но эта вещь позволяет работать случаю n=8. Почему?
Записан

С уважением, asker
sss
Специалист

ru
Offline Offline

« Ответ #5 : 09-10-2006 00:40 » 

Код:
// winnt.h 

MAXIMUM_WAIT_OBJECTS == 64

Записан

while (8==8)
asker
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 09-10-2006 07:34 » 

Тогда возможно понятно почему не работает с WFMO, но с другой стороны "а почему работает" , ведь количество объектов явно превосходит MAXIMUM_WAIT_OBJECTS.
И еще не ясен вопрос с WFSO никаких подобных ограничений нет (и быть не может Улыбаюсь)
Седня обязательно посмотрю...

P.S.: а про MAXIMUM_WAIT_OBJECTS я и не знал, не зря поговорка есть "смотришь в книгу, а видишь ..." Улыбаюсь
Записан

С уважением, asker
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #7 : 23-01-2008 08:42 » 

у меня чем то похожая загвоздка, правда не совсем. Короче, ситуация такая:

имеется глобальное событие , которое задумано использоваться для сообщения потоку о том, что надо бы завершиться.
HANDLE event=::CreateEvent(0,1,0,0);

запускаю поток, так:
Код:
::AfxBeginThread(thread1,event);

 в качестве параметра передаю хендл на событие, событие в этот момент сброшено, поток такой:
Код:
//поток для постоянного чтения сообщений
UINT thread1(LPVOID param)
{
HANDLE event=(HANDLE)param;

for(;;)
{
Sleep(1000);

//смотрим, не надо ли выйти
::AfxMessageBox("проверка на выход из потока",MB_SYSTEMMODAL);

if(WAIT_OBJECT_0==::WaitForSingleObject(event,0))
{
::AfxMessageBox("выход из потока",MB_SYSTEMMODAL);
break;
}
}

return 0;
}

по нажатию на кнопку завершаю поток выставлением события, для эксперимента делаю так:

Код:
	Sleep(5000);
::SetEvent(event);
Sleep(5000);
::AfxMessageBox("10 сек после нажатия прошло",MB_SYSTEMMODAL);

запускаю программу, появляется сообщение о запуске потока, затем в потоке, как и ожидается, раз в секунду появляется окно с сообщением (проверка на выход из потока).
Жму на кнопку - зависает всё , и основной процесс (ну это вроде так и должно быть) и ПОТОК (?) , потому что во время слипа 5 секунд окошко в диалоге не выскакивает, потом , когда выставляется событие, ждётся ещё 5 секунд - по истечении всех 10 секунд выясняется, что поток всё это время так и висел, ибо после этого он благополучно сообщает -

"проверка на выход из потока",
"выход из потока",

что я не правильно делаю? Или так нельзя делать ?
Записан

sss
Специалист

ru
Offline Offline

« Ответ #8 : 23-01-2008 10:03 » 

Это эффект использования ::AfxMessageBox(...,MB_SYSTEMMODAL). Попробуй вместо окон сообщений выводить или в лог файл или куда еще... Замораживая основной процесс ты замораживаешь и цикл выборки сообщений, что приводит к задержке в вызове ::AfxMessageBox в доп. потоке... И еще, вопрос на понимание, можно вызвать два ::AfxMessageBox в одном процессе одновременно?
Записан

while (8==8)
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #9 : 23-01-2008 10:12 » 

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

Выложи проектик. Я так понял это тестовый?
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #10 : 23-01-2008 10:51 » 

Джон, ага, понимаю... переделал через указатель теперь. Но всё же копия тоже неплохо работало )) - хендл он сам по себе указатель, по идее

sss, два в одном процессе низя - блокируется очередь сообщений (вернее обрабатывается боксом)

Джон, sss, хм... дело было, похоже, действительно в боксах - я их убрал, а для индикатора оставил 100% нагрузку процессора в потоке (Sleep из потока убрал). В кнопке сделал

Код:
::SetEvent(event);
Sleep(5000);

и всё как надо - 100% загрузка убралась сразу , главное окно стало активно через 5 секунд. Для контроля (а вдруг этот слип мешает ?) убрал из потока ожидание сообщения - поток так и крутился в и в течение этих 5 секунд 100% загрузка не убиралась.

Вроде разобрался Улыбаюсь
Записан

Scorp__)
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 23-01-2008 11:12 » 

Алексей1153++, на мой взгляд, с точки зрения производительности (еще понятности и красивости Улыбаюсь ), лучше завершать поток по флагу (bool), если он крутится в цикле как у тебя. По времени там получится одна проверка, а WaitForSingleObject - вызов + переключение в режим ядра + возможное переключение потока + та самая проверка Улыбаюсь

Завершать по событию имеет смысл, когда поток чего-то ждет все время. Например, поступления каких-то данных. В общем, когда поток асинхронный и часто будет находится в ожидании. Тогда в это же ожидание можно впихнуть событие завершения, но это уже будет WaitForMultipleObjects.
Записан

- А Вы сами-то верите в привидения?
- Конечно, нет, - ответил лектор и медленно растаял в воздухе.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #12 : 23-01-2008 11:27 » 

Scorp__), я обычно по флагу и делаю , тем более , что поток завершается при завершении программы. Просто решил разобраться с событиями - всё как-то руки до них не доходили Улыбаюсь
Записан

Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines