C++Builder
  Начало   Форум   Помощь Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Вопрос по странному поведению TThread  (Прочитано 9697 раз)
Zor
Глобальный модератор


Сказали спасибо: +158/-30
Offline

Сообщений: 2946


« : 28 Март 2008, 01:34:10 »

Ситуация:
Создаю пачку размороженых ниток (TThread[], CreateSuspended = false)

Код
// код потока должен выполнить инит и остановится:
Execute()
{
// init ...
while (!Terminated)
 {
 Suspended = true; // (point:A)
 // something ...
 }
// done ...
}
 
// после создания жду пока все добегут до состояния "заморожено" (или Terminated если облом):
while (1)
 {
 if (Threads[]->Terminated || Threads[]->Suspended) break;
 }

Так вот, проблема в том, что иногда один-два потока (чаще один) где то застревает, никогда не доходя до (point:A)
WTF? И еще - отладчиком BC6 можно ходить по коду в потоках (F7/F8)?
« Последнее редактирование: 19 Октябрь 2011, 14:12:00 от volvo877 » Записан
OVE
Участник


Сказали спасибо: +67/-0
Offline

Сообщений: 72


« Ответ #1 : 28 Март 2008, 08:33:13 »

Попробуйте

Код
while (1)
 {
 Application->ProcessMessages();
 if (Threads[]->Terminated || Threads[]->Suspended) break;
 }
« Последнее редактирование: 19 Октябрь 2011, 14:12:17 от volvo877 » Записан
serg76
Участник


Сказали спасибо: +38/-2
Offline

Сообщений: 575


« Ответ #2 : 28 Март 2008, 09:21:53 »

Цитировать
Создаю пачку размороженых ниток (TThread[], CreateSuspended = false)

можно выложить пример, как создавать потоки в цикле
например for(int i=0;i<7;i++)
Записан
bred
А моск есть?
Участник


Сказали спасибо: +6/-0
Offline

Сообщений: 387

Нет - это фантастика!


« Ответ #3 : 28 Март 2008, 10:03:39 »

И еще - отладчиком BC6 можно ходить по коду в потоках (F7/F8)?
В принципе можно, но во-первых нет никакой гарантии что последовательность переключений между потоками будет производится как бы она производилась в нормальном режиме (да и вообще нет гарантии что она вообще будет производится;) ), а во-вторых по большей части такая отладка заканчивается в лучшем случае повисанием ПК с попытками вырубания билдера, захватившего все ресурсы, в течении минут 10 (у меня диспетчер задач однажды убивал билдер порядка 20-30 минут), либо просто перезагрузкой от кнопки "ресет". Кстати перезагружать машину после такой отладки (даже если все вроде прошло чудесно) все равно скорее всего придется .
Записан
Doga
Давний друг


Сказали спасибо: +31/-1
Offline

Сообщений: 241


« Ответ #4 : 28 Март 2008, 14:40:35 »

Привет.

Когда поток замораживается, система просто перестаёт выделять ему процессорное время. Возможно, причина в этом. Попробуйте использовать вместо Suspended какой-либо другой дополнительный флаг для проверки состояния потока.

Если у потока FreeOnTerminate = true, то в случае коректоной обработки флага Terminated, поток может самостоятельно завершить свою работу. Возможно, что Вы пытаетесь обратиться к уже не существующему потоку. Понятно, что последствия, в данном случае, не предсказуемы...
Записан
Zor
Глобальный модератор


Сказали спасибо: +158/-30
Offline

Сообщений: 2946


« Ответ #5 : 28 Март 2008, 14:43:49 »

2 OVE я обычно ставлю Sleep() вместо ProcessMessages(). Хотя это мысль - надо исходники порыть...
2 serg76 также как и прочие объекты:
for (int i = 0; i < 7; i++) Threads = new (nothrow) TMyThread(false);
Записан
Zor
Глобальный модератор


Сказали спасибо: +158/-30
Offline

Сообщений: 2946


« Ответ #6 : 28 Март 2008, 14:49:24 »


2 Doga ну уж если Suspended криво работает - можно сразу на апи переходить. FrеeOnTerminate не используется - надо же узнать почему поток незапланировано вылетел.
Записан
Doga
Давний друг


Сказали спасибо: +31/-1
Offline

Сообщений: 241


« Ответ #7 : 28 Март 2008, 15:12:13 »

Я не говорил, что Suspended криво работает.

Приведённый Вами код слишком сильно сокращён и не позволят представить полную картину происходящего в потоке. Давайте больше кода

Цель заморозки потоков не понятна. Зачем ожидать заморозки потоков или их завершения сразу после их создания? Не проще ли тогда создать их замороженными?
Записан
Asher
Администратор


Сказали спасибо: +111/-5
Offline

Сообщений: 425


« Ответ #8 : 28 Март 2008, 16:29:34 »

Привет всем.
Sleep на ожидание отработки может не помочь, с ProcessMessage уже лучше.
Я в таком случае делал цикл ожидания, внутри которого ProcessMessage() и ::SwitchToThread();
Записан
serg76
Участник


Сказали спасибо: +38/-2
Offline

Сообщений: 575


« Ответ #9 : 28 Март 2008, 16:44:02 »

Код
for (int i = 0; i < 7; i++) Threads = new (nothrow) TMyThread(false);

эт наверно для тех, кто знал и подзабыл 

и что надо для "nothrow" подключить ?
у меня Undefined symbol
Записан
Zor
Глобальный модератор


Сказали спасибо: +158/-30
Offline

Сообщений: 2946


« Ответ #10 : 28 Март 2008, 20:35:12 »

2 serg76 // Threads [ i ] = new ... , ачипятка  
2 Asher проверил - никакой принципиальной разницы между Sleep и ProcessMessages тут нет. Дело вкуса. Разве что без тормоза Sleep лог успевает вырасти в разы больше

*********************************

Всем спасибо разобрался. Дело оказалось во врожденной глючности TThread.
оригинал статьи, если кому интересно: http://delphi.newswhat.com/geoxml/forumhistorythread?groupname=borland.public.delphi.nativeapi.win32&messageid=473950eb@newsgroups.borland.com

А вот виновник торжества:

Код
procedure TThread.Resume;
var
 SuspendCount: Integer;
begin
 SuspendCount := ResumeThread(FHandle);
                               <<<< вот здесь система переключает поток, и если он успевает дойти до Suspend()
                               <<<< флаги состояния показывают фигню.
 CheckThreadError(SuspendCount >= 0);
 if SuspendCount = 1 then
   FSuspended := False;
end;

 напоминает новую реинкарнацию DivideByZero/RunTimeError200, правда?
« Последнее редактирование: 19 Октябрь 2011, 14:12:36 от volvo877 » Записан
serg76
Участник


Сказали спасибо: +38/-2
Offline

Сообщений: 575


« Ответ #11 : 09 Апрель 2008, 11:26:14 »

Вопрос в тему

несколько потоков используют одну ф-ю заполнения listbox

необходимо использовать Критический раздел или достаточно вызывать по Synchronize ?
Записан
bred
А моск есть?
Участник


Сказали спасибо: +6/-0
Offline

Сообщений: 387

Нет - это фантастика!


« Ответ #12 : 09 Апрель 2008, 12:51:29 »

по идее синхронайза должно хватить.
Записан
serg76
Участник


Сказали спасибо: +38/-2
Offline

Сообщений: 575


« Ответ #13 : 09 Апрель 2008, 16:04:54 »

в .h файле mytrd *mtr;
в .cpp
Код
for (i = 0; i < 7; i++) mtr[i]= new (nothrow) mytrd(true);

выдает ошибку: VCL style classes must be constructed using operator new
оператор new есть, что не так 

Записан
Zor
Глобальный модератор


Сказали спасибо: +158/-30
Offline

Сообщений: 2946


« Ответ #14 : 09 Апрель 2008, 20:44:46 »

а целиком?
Записан
serg76
Участник


Сказали спасибо: +38/-2
Offline

Сообщений: 575


« Ответ #15 : 10 Апрель 2008, 09:31:31 »

создаю поток mytrd
идея в том, что у всех потоков одинаковый код, но на стадии инициализации переменным присваиваются разные значения
например "com1","com2","com3" и т.д.

Цитировать
а целиком?
а что целиком?
Записан
bred
А моск есть?
Участник


Сказали спасибо: +6/-0
Offline

Сообщений: 387

Нет - это фантастика!


« Ответ #16 : 10 Апрель 2008, 11:21:10 »

в .h файле mytrd *mtr;
в .cpp
Код
for (i = 0; i < 7; i++) mtr[i]= new (nothrow) mytrd(true);
выдает ошибку: VCL style classes must be constructed using operator new
оператор new есть, что не так 
что-то мне кажется что те надо добавить скобочки в объявление:
Код:
mytrd *mtr[N];
Записан
serg76
Участник


Сказали спасибо: +38/-2
Offline

Сообщений: 575


« Ответ #17 : 10 Апрель 2008, 12:11:26 »

2bred спасибо помогло

в динамическом выделении слабо орентируюсь

а как замутить если кол-во потоков заранее неизвесно ?
Записан
oxotnik
Глобальный модератор


Сказали спасибо: +100/-15
Offline

Сообщений: 2425


« Ответ #18 : 10 Апрель 2008, 14:01:04 »

а как замутить если кол-во потоков заранее неизвесно ?

я так делал, правда через CreateThread  (собственно уже где то размещал):
Код
//в *.hpp главной формы (у меня, а там делай где хочешь)
#include
using namespace std;
class TMainForm : public TForm
{
...
public:
deque <HANDLE> m_MyThread;
....
};
 
//в *.cpp
 
m_MyThread.push_back(CreateThread( NULL , 0 , SaveDocObj, (LPVOID)id, 0 , NULL )); // помещаем хендл потока в динамический массив
 
//при закрытии формы (приложения) ждем завершения всех потоков:
 
void __fastcall TMainForm::FormCloseQuery(TObject *Sender, bool &CanClose)
{
 if (m_MyThread.size()>0)
    {
      HANDLE *MyThread = new HANDLE[m_MyThread.size()];
      for(unsigned int n=0;n <m_MyThread.size();n++)
         {
           MyThread[n] = m_MyThread[n];
         }
      DWORD hEvent = WaitForMultipleObjects(m_MyThread.size(), MyThread, TRUE, INFINITE);
      delete [] MyThread;
      if (hEvent != WAIT_OBJECT_0)
         {
           CanClose = false;
           return;
         }
    }
 
Записан
serg76
Участник


Сказали спасибо: +38/-2
Offline

Сообщений: 575


« Ответ #19 : 10 Апрель 2008, 16:43:03 »

2oxotnik спасибо, буду грызть
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  




....

Powered by SMF 1.1.21 | SMF © 2025, Simple Machines
Страница сгенерирована за 0.078 секунд. Запросов: 19.