C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Как получить доступ к данным в потоке?
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 в потоке?
}
//----------


smile.gif
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. В самих функциях чтения/записи операции обращения к свойству ограничить блоками
CODE
EnterCriticalSection(&CS_FNErr);
... //и
LeaveCriticalSection(&CS_FNErr);
, где CRITICAL_SECTION CS_FNErr; — член класса компонента TCTSCom.
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);
}

Вечером попытаюсь это сделать с применением критических секций. Спасибо за подсказку. smile.gif
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); это принял

ohmy.gif и не будет работать
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 лучше будет.

Вернуться в Вопросы программирования в C++Builder