| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C++ Builder > Завершение потока |
| Автор: Bima 7.12.2006, 08:00 | ||||
| Взял пример для реализации потока. Я переделал его под 3 потока, но не могу остановить потоки, когда они запущены. вот пример:
Заголовочный файл:
на форме 4 кнопки и 3 лайбела. первые три кнопки запускают потоки, 4 кнопкой я пытаюсь их все остановить. Как мне сделать, что бы это все выполнялось правильно??? |
| Автор: takedo 7.12.2006, 08:15 |
| Слушай, я в билдере не очень силен, но ты почитай темы сперва про потоки в разделе API, там очень много про это. А что касательно твоего кода, то вообще то ты знаешь, что обозначает флаг MDownload[0]->FlagExit(true);? Ты ведь для каждого потока его вызываешь при создании формы, а затем я так понял и по кнопке 4. То есть ты его сперва останавливаешь, а потом ещё раз? Может ты знаешь про потоки больше меня, может нет, но все таки ты должен знать, что поток - это отдельня фукнция, в которой ты и работаешь, когда ты говоришь о выходе из потока, ты просто выходишь из этой функции, обратного захода без порождения нового потока нету. Вообще-то дождись конечно билдеристов, но пока тебе не помогли, почитай раздел форума по API и используй прямо от туда все API - билдер ведь их поддерживает по умолчанию, а уже потом начинай со временем применять билдеровские классы. мне кажется, так будет проще. Да, кстати, хорошо описано в Мешков, Тихомиров книга про MFC, не раз в форуме упоминалась, точное название не помню(давно уже ничего толком не программировал, книга эта настольная была всегда) удачи |
| Автор: Bima 7.12.2006, 08:41 |
| Вначале я вызываю эту функцию MDownload[i]->FlagExit(true) для того, что бы поток не запустился сразу и инициализирую переменную FlagQuit для каждого потока. А потом запускаю поток командой MDownload[i]->Resume(); Причем, если я нажимаю несколько раз на первую кнопку, то столько раз запускается первый поток. но пока поток работает, я остановить его не могу |
| Автор: Bima 7.12.2006, 09:23 | ||
вот переделанный код:
потоки работают нормально, претензий нет, но при нажатии на кнопку 4 (процедура Button4Click), я не могу остановить потоки... счетчики работают |
| Автор: dumb 7.12.2006, 09:46 | ||
кстати, а чем тебе не угодило свойство Terminated из TThread? - его вполне достаточно. зачем тебе FlagQuit твой? |
| Автор: Bima 7.12.2006, 09:56 | ||||||
Этот код тоже не работает!!!
если я пишу в коде на 4 кнопке следущее:
то после нажатия на нее (все потоки предварительно запустил), происходит останавливание 3 потока, но при повторном запуске его (нажать на кнопку 3) выскакивает ошибка! |
| Автор: GL_basik 7.12.2006, 10:34 | ||
Terminate будет работать если установить в процедуре execute пердусмотреть выход по свойтву Terminated. Например
Поток завершается только тогда, когда прекращается выполнение Execute. Кроме того есть жесткое завршние потока с помощью API функции TerminateThread. Что касается ошибки. То уствнови свойство FreeOnTerminate=false. Иначе для повторного запуска поток нужно завново инициальзировать. Только не забудь очистить память, после завершния прораммы. |
| Автор: Bima 7.12.2006, 10:48 | ||||
Переписывание цикла "до".... ничего не даст, так как программа туда заходит только один раз при инициализации, потом она туда не заходит. Ставил там breakPoint и проверял. почему это происходит не знаю Terminate завершает поток, отсюда и ошибка выскакивает, так как я пытаюсь использовать поток, который завершился.
пытался я так делать, но в этом случае поток все равно завершается, и не запускается, хотя в этом случае ошибку не выдает. Хотя так и должно быть, так как поток завершен, в памяти он остался, но не запущен. пока задача не решена Добавлено @ 10:58 Что бы было понятнее, я напишу, что я хочу сделать. Есть программа в которой есть несколько задач. Эти задачи могут выполнятся длительное время и они должны выполнятся параллельно. По истечении определенного времени(TimeOut), если задача не выполнена, задача должна быть завершена (Это реализуется легко, если знать, как корректно завершить задачу). Есть еще одно условие в програме - задачи должны через определенное время перезапускаться. Из всего написаного я сделал вывод, что нужно использовать потоки, которые будут запускаться по таймеру. Постоянно создовать потоки нет смысла и выгружать их из памяти тоже, поэтому я решил, что лучше создать все потоки при создании программы и убить их все во время завершения программы. Для эмуляции задачи написал простой счетчик (см. код программы), который хочу остановить по нажатию кнопки. Дальше при реализации завершения потока быду вставлять таймеры и двигаться от простого к сложному. Вот вроде и вся реализация, которою я надумал. |
| Автор: GL_basik 7.12.2006, 11:01 | ||
Судя по приведенному коду, после инициализации она уходит в цикл с параметром и естественно проверки условия завершния не происходит. Пока не завершится этот цикл. |
| Автор: Bima 7.12.2006, 11:24 | ||
что разве в этом коде нет проверки условия?
я думал, что после выполнения коменд внутри цикла (Synchronize и Sleep) управление передается на проверку условия (достигло ли i значения 1000 и нет ли флагов FlagQuit, Terminated) или я не прав??? |
| Автор: dumb 7.12.2006, 11:47 | ||||
| Bima, фор надо было так сделать:
а если тебе нужно притормаживать потоки с возможностью их продолжения, то так и надо было говорить. в таком случае тебе нельзя выходить из Execute. для приостановки пользоваться либо Suspend(тут торможение происходит в любом месте цикла, что зачастую неприемлимо), либо доп.флагом. например так:
|
| Автор: Bima 7.12.2006, 14:13 | ||||||
Виноват, прогнал dumb спасибо за подсказку. Реализовал я примерно так, как ты написал. Вроде работает так как я хотел. Вот код:
Остался последний вопрос. я при закрытии формы убиваю потоки так:
Стоит ли это делать? Вроде я поставил FreeOnTerminate=true, но все равно сомневаюсь, освободится ли память после потоков или нет? |
| Автор: GL_basik 7.12.2006, 15:44 | ||
Память после потоков освободится. Я проверял. Это нормальное завершение потока. При выходе из процедуры Execute, объект уничтожается. |
| Автор: Bima 7.12.2006, 15:47 |
| все, тема закрыта, всем спасибо. |
| Автор: dumb 7.12.2006, 15:47 | ||
ну, это не ты прогнал, а я. если ты закрываешь главную форму(т.е. приложение после этого завершается), то можешь, в принципе, вообще не беспокоиться о потоках - система грохнет все, что было порождено твоим процессом. но по правилам хорошего тона - завершать нужно. и мало того - еще и подождать в основном потоке завершения остальных. чет ты опять наворотил...
зачем ты тут флаг в цикле выставляешь, если он является механизмом внешнего воздействия на поток? |
| Автор: Bima 7.12.2006, 15:58 | ||
Ну вот, только пометил, что вопрос решенный
Здесь я ставлю флаг, что бы после выполнения цикла (for) и при первом заходе сюда программа останавливалась на цикле (do... while). Вот и у меня получается, что при создании формы потоки создаются и крутятся на цикле (do... while) и ждут, когда флаг FlagQuit будет false. После этого выполняется цикл (for) и если во время выполнения, флаг FlagQuit будет принудительно сброшен в true то он снова перейдет на цикл (do... while) и все пойдет сначала. Если цикл (for) дойдет до своего конца, то что бы снова уйти в паузу, как раз и нужна эта команда FlagQuit = true. если есть более рациональное решение, то прошу пример в студию |
| Автор: dumb 7.12.2006, 16:12 | ||
а... ну да.. забыл этот момент из описания задачи. а ProcessMessages то зачем? - не место ему тут. |
| Автор: Vyacheslav 7.12.2006, 16:33 | ||||||||||||
Угу Вообще - то Я бы не стал так делать. Terminate не завершает насильно нитку подобно TerminateThread, а лишь устанавливает Terminated в true. Так что, вызов Terminate() не гарантирует, что поток завершится. Задержка может быть вызвана либо ошибкой программиста( не удосужился в Execute установить проверку флага Terminated ), либо потому, что время между проверками относительно длительное. Последнее не очень страшно, если приложение должно продолжить работу после завершения нитки и тогда FreeOnTerminate к месту, но ... если приложенин должно тут же завершиться, то могут (не обязательно, но всетаки возможно) возникнуть проблемы. Я бы на твоем месте поступил бы следующим образом . Установил бы FreeOnTerminate=false и уничтожал бы так
И еще одно. Почему не используешь внутрение средства для временной отстановки нитки Ведь вот это все
и этого
просто можно заменить одно строчкой
и нитка замрет Правда в код по уничтожению ниток придется ввести еще проверку
|
| Автор: Bima 8.12.2006, 07:16 | ||||||||
я сначала пробовал этот метод, но загвостка в том, что он ПРИОСТАНАВЛИВАЕТ поток, а потом командой m_Download[0]->Resume() его продолжает с того места откуда он остановился. А мне нужно что бы поток сбросился (но не убился) и потом его снова возобновить С НАЧАЛА. Я уже подумываю, что может лучше будет каждый раз убивать потоки и потом их снова создавать, а то инструкция:
меня сильно настораживает. Вроде как бы программа в это время не должна работать, а она постоянно отрабатыват циклы задержки (sleep) с проверкой на флаг. Что лучше в этом случае, постоянно создавать и убивать потоки или использовать цикл задержки (sleep) ???
Vyacheslav проясни еще один момент. А если поток ушел в длительную обработку информации (не как у меня в примере), допустим команда в потоке ждет информацию от устройства, а устройство умерло. Что в этом случае произойдет, при уничтожении потока, программа будет ждать пока завершиться Execute??? Я вот про это место пишу:
Я правильно помнимаю, что в этом случае, поток вообще не завершиться или нет??? |
| Автор: Vyacheslav 8.12.2006, 11:18 | ||||||
Совершенно верно.
Что бы насильно завершить поток нужно использовать АPI-шную функцию. Если это тебе нужно то в твоем MyThred напиши еще один метод Примерно так
Этот точно должен грохнуть нитку |
| Автор: Bima 8.12.2006, 13:02 |
| Vyacheslav а как Handle потока получить? и что передавать в exitCode??? на реальном примере как это написать??? |
| Автор: Vyacheslav 8.12.2006, 13:32 | ||||
Его не надо получать
exitCode - просто код возврата, что бы потом можно проанализировать с каким кодом завершился тред Если код не интересут, то
|
| Автор: Bima 8.12.2006, 14:19 |
| У меня ошибку при компиляции выдает: [C++ Error] kod.cpp(73): E2227 Extra parameter in call to _fastcall MyTread::TerminateThread() Вроде везде все правильно объявил функцию.... даже вначале прописал: #include "winbase.h" почему не выходит не пойму |
| Автор: Vyacheslav 8.12.2006, 14:41 | ||
|
| Автор: Bima 8.12.2006, 14:59 |
| не выходит ругается на ноль в конце: [C++ Error] kod.cpp(73): E2034 Cannot convert 'const unsigned int' to 'void *' |
| Автор: Vyacheslav 8.12.2006, 15:45 | ||
|
| Автор: Bima 11.12.2006, 06:45 | ||
| Все заработало. Vyacheslav, спасибо за подсказки и за реализацию кода. Vyacheslav скажи, а зачем в последнем топике нужно было приостанавливать поток???
Как я понимаю, здесь нужно именно убить поток, а если он не приостановится???? так и будет висеть в команде Suspend??? |
| Автор: Vyacheslav 11.12.2006, 11:01 |
| Приостановится он всегда. А приостановить его стоит для того, что бы не словить исключение при его уничтожении из-за того, что в момент уничтожения он продолжает крутится. Хотя вполне возможно TerminateThread сама предварительно перед уничтожением приостанавлиавент егою |
| Автор: Bima 11.12.2006, 11:18 |
| всем спасибо. тема закрыта |