| Valery_52 | 
| Отправлено: 22.03.2005, 08:01 |  | 
| 
 Ученик-кочегар
 
 Группа: Участник
 Сообщений: 25
 
 
 
  
 | Здравствуйте! Пишу на ВСВ6. Компонент содержит поток.
 Подскажите пожайлуста, как правильно обращаться к членам данных компонента в потоке?
 #ifndef CTSComH
 #define CTSComH
 //---------------------------------------------------------------------------
 #include
 #include
 
 class __declspec(package)MyCTS;
 //---------------------------------------------------------------------------
 class PACKAGE TCTSCom : public TComponent
 {
 private:
 class MyCTS *pMCTS;
 
 protected:
 public:
 int FNErr;
 void __fastcall POpen(int );
 void __fastcall PClose(void);
 __fastcall TCTSCom(TComponent* Owner);
 
 __property int NErr = { read =FNErr, write=FNErr};
 __published:
 
 };
 //---------------------------------------------------------------------------
 class MyCTS : public TThread
 {
 friend class TCTSCom;
 private:
 protected:
 public:
 void __fastcall Execute();
 __fastcall MyCTS(bool CreateSuspended);
 };
 //----------------------------------------------------------------------------
 #endif
 
 Файл .cpp
 #include
 #pragma hdrstop
 #include "CTSCom.h"
 #pragma package(smart_init)
 
 TCTSCom * pCts; // Указатель на объект
 
 //---------------------------------------------------------------------------
 static inline void ValidCtrCheck(TCTSCom *)
 {
 new TCTSCom(NULL);
 }
 //---------------------------------------------------------------------------
 __fastcall TCTSCom::TCTSCom(TComponent* Owner)
 : TComponent(Owner)
 {
 FNErr =0; // Здесь все нормально
 }
 //---------------------------------------------------------------------------
 namespace Ctscom
 {
 void __fastcall PACKAGE Register()
 {
 TComponentClass classes[1] = {__classid(TCTSCom)};
 RegisterComponents("My", classes, 0);
 }
 }
 //---------------------------------------------------------------------------
 void __fastcall TCTSCom::SetDevice(TDeviceCom Value)
 { }
 //---------------------------------------------------------------------------
 void __fastcall TCTSCom::PClose(void)
 {
 if (pMCTS->FreeOnTerminate) pMCTS->Terminate();
 FNErr =0; // Здесь все нормально
 }
 //---------------------------------------------------------------------------
 void __fastcall TCTSCom::POpen(int NCOM)
 {
 FNErr = NCOM; // Здесь все нормально
 
 pMCTS = new MyCTS(false);
 pMCTS->Priority = tpLower;
 pMCTS -> FreeOnTerminate = true;
 }
 //---------------------------------------------------------------------------
 __fastcall MyCTS::MyCTS(bool CreateSuspended)
 : TThread(CreateSuspended)
 { }
 //---------------------------------------------------------------------------
 void __fastcall MyCTS::Execute()
 {
 // FNErr = 2; если так, то ошибка при компиляции
 pCts->NErr = 2; // A здесь указатель pCts = NULL
 Как получить доступ к NErr в потоке?
 }
 //----------
 
 
 
   | 
|  | 
| Asher | 
| Отправлено: 22.03.2005, 08:31 |  | 
|  
 Мастер участка
 
 Группа: Модератор
 Сообщений: 550
 
 
 
  
 | Привет. А почему pCts не должен быть равен NULL.
 Из кода это никак не слудует.
 Он сам встречается только два раза — в объявлении TCTSCom * pCts;
 и попытке вызова pCts->NErr = 2;
 А инициализация где?
 | 
|  | 
| Rius | 
| Отправлено: 22.03.2005, 08:44 |  | 
|  
 Мастер участка
 
 Группа: Участник
 Сообщений: 321
 
 
 
  
 | вариант: 1. Создать в классе потока указатель на компонент TCTSCom.
 2. После создания потока и до его запуска присвоить указателю адрес компонента this.
 3. Не делать глобальных переменных.
 4. Чтение и запись свойства производить через функции, типа
 | CODE |  | int NErr = {read = FGetNErr, write = FSetNErr}; 
 | 
 5. В самих функциях чтения/записи операции обращения к свойству ограничить блоками
 , где CRITICAL_SECTION CS_FNErr; — член класса компонента TCTSCom.| CODE |  | EnterCriticalSection(&CS_FNErr); ... //и
 LeaveCriticalSection(&CS_FNErr);
 | 
 6. Инициализация CS_FNErr в конструкторе компонента:
 
 | CODE |  | InitializeCriticalSection(&CS_FNErr); | 
 Удаление в деструкторе:
 
 | CODE |  | DeleteCriticalSection(&CS_FNErr); | 
 
 Отредактировано Rius — 22/03/2005, 10:52
 | 
|  | 
| Valery_52 | 
| Отправлено: 22.03.2005, 13:32 |  | 
| 
 Ученик-кочегар
 
 Группа: Участник
 Сообщений: 25
 
 
 
  
 | В том то и дело, что яне знаю как проинициализировать. Инициализация то провелась как бы в static inline void ValidCtrCheck(TCTSCom *)
 {
 new TCTSCom(NULL);
 }
 
 Вечером попытаюсь это сделать с применением критических секций. Спасибо за подсказку.
   | 
|  | 
| Asher | 
| Отправлено: 22.03.2005, 13:43 |  | 
|  
 Мастер участка
 
 Группа: Модератор
 Сообщений: 550
 
 
 
  
 | | QUOTE |  | Инициализация то провелась как бы в static inline void ValidCtrCheck(TCTSCom *)
 {
 new TCTSCom(NULL);
 }
 | 
 где конкретно в приведенном коде инициализируется pCts
 Может вы хотели получить это?
 pCts = new TCTSCom(NULL);
 P.S. В Вашем конкретном случае никакие критические секции нипричем.
 | 
|  | 
| Valery_52 | 
| Отправлено: 23.03.2005, 08:05 |  | 
| 
 Ученик-кочегар
 
 Группа: Участник
 Сообщений: 25
 
 
 
  
 | Программирование на ВСВ,для меня, больше всего напоминает поиск единственно истинного пути.Компилятору постоянно что-то не нравится.
 TCTSCom * pCts = new TCTSCom(0); не годится
 TCTSCom * pCts = new TCTSCom(this);не годится
 pCts = new TCTSCom(0); тоже
 pCts = &TCTSCom(0); это принял, и впихнул я это после
 pMCTS->Priority = tpLower;Подскажите, правильно ли, что инициализация проведена в этом месте?
 Теперь надо будет как то проверить pMCTS, правильное ли
 он получил значение. Прога работает неправильно.FNErr =145, а
 я такое значение нигде не присваиваю.
 Еще раз спасибо за помощь.
 | 
|  | 
| Георгий | 
| Отправлено: 23.03.2005, 09:44 |  | 
| 
 Почетный железнодорожник
 
 Группа: Модератор
 Сообщений: 874
 
 
 
  
 | | QUOTE (Valery_52 @ 23/03/2005, 08:05) |  | pCts = &TCTSCom(0); это принял | 
 
  и не будет работать | 
|  | 
| Rius | 
| Отправлено: 23.03.2005, 12:01 |  | 
|  
 Мастер участка
 
 Группа: Участник
 Сообщений: 321
 
 
 
  
 | ctscom.cpp 
 | CODE |  | #pragma hdrstop #include "CTSCom.h"
 #pragma package(smart_init)
 
 #include "mycts.h"
 //---------------------------------------------------------------------------
 static inline void ValidCtrCheck(TCTSCom *)
 {
 new TCTSCom(NULL);
 }
 //---------------------------------------------------------------------------
 __fastcall TCTSCom::TCTSCom(TComponent* Owner)
 : TComponent(Owner)
 {
 InitializeCriticalSection(&CS_FNERR);
 NErr =0; // Здесь все нормально
 }
 //---------------------------------------------------------------------------
 
 __fastcall TCTSCom::~TCTSCom()
 {
 DeleteCriticalSection(&CS_FNERR);
 }
 //---------------------------------------------------------------------------
 namespace Ctscom
 {
 void __fastcall PACKAGE Register()
 {
 TComponentClass classes[1] = {__classid(TCTSCom)};
 RegisterComponents("My", classes, 0);
 }
 }
 //---------------------------------------------------------------------------
 //void __fastcall TCTSCom::SetDevice(TDeviceCom Value)
 //{ }
 //---------------------------------------------------------------------------
 void __fastcall TCTSCom::PClose(void)
 {
 // if (pMCTS->FreeOnTerminate) pMCTS->Terminate();//объект удаляется при закрытии, поэтому метод вызывать нельзя
 NErr =0; // Здесь все нормально
 }
 //---------------------------------------------------------------------------
 void __fastcall TCTSCom::POpen(int NCOM)
 {
 NErr = NCOM; // Здесь все нормально
 pMCTS = new MyCTS(true);//если с false, то поток сразу запускается
 //но так как параметры ещё не заданы ко времени его запуска, все вылетает
 //поэтому CreateSuspended=true; и после задания параметров — Execute
 pMCTS->Priority = tpLower;
 pMCTS->FreeOnTerminate = true;
 pMCTS->pCts = this;
 pMCTS->Execute();
 }
 //---------------------------------------------------------------------------
 
 void __fastcall TCTSCom::SetNErr(int value)
 {
 EnterCriticalSection(&CS_FNERR);
 if(FNErr != value) {
 FNErr = value;
 }
 LeaveCriticalSection(&CS_FNERR);
 }
 //---------------------------------------------------------------------------
 
 int __fastcall TCTSCom::GetNErr()
 {
 int result;
 EnterCriticalSection(&CS_FNERR);
 result = FNErr;
 LeaveCriticalSection(&CS_FNERR);
 return result;
 }
 
 | 
 ctscom.h
 
 | CODE |  | #ifndef CTSComH #define CTSComH
 //---------------------------------------------------------------------------
 #include <SysUtils.hpp>
 #include <Classes.hpp>
 #include <Controls.hpp>
 
 class MyCTS;
 //---------------------------------------------------------------------------
 class PACKAGE TCTSCom : public TComponent
 {
 private:
 CRITICAL_SECTION CS_FNERR;
 int FNErr;
 void __fastcall SetNErr(int value);
 int __fastcall GetNErr();
 class MyCTS *pMCTS;
 protected:
 public:
 void __fastcall POpen(int );
 void __fastcall PClose(void);
 __fastcall TCTSCom(TComponent* Owner);
 __fastcall ~TCTSCom();
 __published:
 __property int NErr = { read=GetNErr, write=SetNErr };
 };
 //----------------------------------------------------------------------------
 #endif
 | 
 mycts.cpp
 
 | CODE |  | //--------------------------------------------------------------------------- 
 
 #include <vcl.h>
 #pragma hdrstop
 
 #include "mycts.h"
 #include "ctscom.h"
 //---------------------------------------------------------------------------
 __fastcall MyCTS::MyCTS(bool CreateSuspended) : TThread(CreateSuspended)
 {
 }
 //---------------------------------------------------------------------------
 void __fastcall MyCTS::Execute()
 {
 // FNErr = 2; если так, то ошибка при компиляции
 pCts->NErr = 2; // A здесь указатель pCts = NULL
 ShowMessage(pCts->NErr);
 //Как получить доступ к NErr в потоке?
 }
 //---------------------------------------------------------------------------
 
 #pragma package(smart_init)
 | 
 mycts.h
 
 | CODE |  | //--------------------------------------------------------------------------- #include <SysUtils.hpp>
 #include <Classes.hpp>
 #include <Controls.hpp>
 
 #ifndef myctsH
 #define myctsH
 //---------------------------------------------------------------------------
 class MyCTS : public TThread
 {
 friend class TCTSCom;
 private:
 protected:
 public:
 TCTSCom * pCts; // Указатель на объект
 void __fastcall Execute();
 __fastcall MyCTS(bool CreateSuspended);
 };
 //---------------------------------------------------------------------------
 #endif
 | 
 
 Отредактировано Rius — 23/03/2005, 14:03
 | 
|  | 
| Valery_52 | 
| Отправлено: 23.03.2005, 15:46 |  | 
| 
 Ученик-кочегар
 
 Группа: Участник
 Сообщений: 25
 
 
 
  
 | Спасибо. Вечером попробую. | 
|  | 
| Valery_52 | 
| Отправлено: 28.03.2005, 07:21 |  | 
| 
 Ученик-кочегар
 
 Группа: Участник
 Сообщений: 25
 
 
 
  
 | Коды попробовал. К сожалению они работают неправильно. Компилятор воспринимает функцию Execute() при инициализации переменных потока как обычную, и поток не создает.Вместо ее надо использовать Resume(). В BCB есть утилита с помощью которой можно просмотреть создаваемые потоки. В общем, прогу я всетаки написал. Правда остался один вопрос. 1.Эта прога контролирует сигналCTS порта СОМ.
 Я открываю порт методом POpen(), создаю нить, которая контролирует вход CTS. В момент включения или выключения сигнала я пытаюсь из функции Execute() вызвать обработчик события. Это мне удается, если я перед вызовом обработчика останавливаю поток, по возвращению из обработчика поток запускаю снова.
 void __fastcall MyCTS::Execute()
 {
 pMCTS -> FreeOnTerminate = true;
 do
 NewCts();
 whle(!Terminated);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCTSCom: NewCts(void)
 {
 if ....
 Suspend();
 if(On_CtsOn) On_CtsOn(this); //обработчик события
 Resume();
 }
 Правильно ли это, может быть как то можно вызвать не останавливая потока?
 
 Еще раз блогодарю за ценную консультацию.
 
 | 
|  | 
| Rius | 
| Отправлено: 28.03.2005, 17:37 |  | 
|  
 Мастер участка
 
 Группа: Участник
 Сообщений: 321
 
 
 
  
 | Лучше так: 
 | CODE |  | Поток::Execute()
 {
 ...
 while(!Terminated)
 {
 if ....
 {
 Syncronize(NewCts);
 }
 }
 }
 void __fastcall TCTSCom: NewCts(void)
 {
 if(On_CtsOn) On_CtsOn(this); //обработчик события
 }
 
 | 
 Все проверки затолкать в код потока Execute, в синхронизирующей функции — только вывод информации (или то, что очень быстро выполняется). Метод, вызванный через Syncronize выполняется в основном потоке VCL, твой поток в это время стоит.
 
 Отредактировано Rius — 28/03/2005, 20:39
 | 
|  | 
| Valery_52 | 
| Отправлено: 29.03.2005, 07:38 |  | 
| 
 Ученик-кочегар
 
 Группа: Участник
 Сообщений: 25
 
 
 
  
 | Да Ваш вариант более универсален, но поток приходиться останавливать. Ко всему, меня растроило ещё одно обстоятельство. Из за использования do ... while процессор загружается на 98%. Придется использовать функцию WaitForSingleObject().
 С уважением Валерий.
 | 
|  | 
| Rius | 
| Отправлено: 29.03.2005, 08:40 |  | 
|  
 Мастер участка
 
 Группа: Участник
 Сообщений: 321
 
 
 
  
 | Чтобы поток (бесконечный цикл) не грузил процессор, можно понизить приоритет потока, либо вставить функцию задержки Sleep(int ms), но тогда можно проворонить событие. Может с действительно WaitForSingleObject лучше будет.
 
 | 
|  |