|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
Переменная в потоке
« : 19 Март 2015, 09:09:24 »
|
|
Сложный вопрос. Попробую расписать схему:
1.
//IdTCPServer1 создает отдельный поток void __fastcall TForm1Main::IdTCPServer1Execute(TIdContext *AContext) { //прием данных и затем вызов функции: String Sdata = AContext->Connection->IOHandler->ReadLn(); ParseJSONValue(Sdata); }
2.
//в функции идет разбор json пакета void ParseJSONValue(String JsonData) { //при первом вызове ParseJSONValue строка JsonData содержит внутри себя нужный параметр. //после обработки JsonData я этот параметр сохраняю в переменную String JsonMemberNameID =тут нужное значение...; //при следующих вызовах ParseJSONValue JsonMemberNameID будет пустым т.к. нужный параметр только в первом пакете //String JsonMemberNameID =пусто; //после этого вызывается следующая функция, где JsonMemberNameID передается вторым параметром ParseJsonArraySens(CoderjimoeJsonArraySens, JsonMemberNameID); }
3.
void ParseJsonArraySens(String CoderjimoeJsonArraySens, String sServerID)
{
String ServerID = sServerID;//вот он наш параметр
//используем его
//***
}
Все это прекрасно работает когда в IdTCPServer1Execute приходит первый пакет json. Первый пакет содержит нужный параметр.
При следующих приходах json данных значение String JsonMemberNameID уже пустое. Нужное значение приходит только в первом пакете.
Как мне в потоке созданном IdTCPServer1Execute запомнить JsonMemberNameID которое инициализируемый при первом вызове IdTCPServer1Execute? Это значение мне нужно для постоянной записи в базу данных при приходе пакетов данных.
Мне надо для потокобезопасности в каждом потоке созданном IdTCPServer1Execute иметь доступ к значению JsonMemberNameID внутри этого потока.
|
|
| « Последнее редактирование: 19 Март 2015, 09:16:10 от SilverFish » |
Записан |
|
|
|
|
OVE
Участник
Сказали спасибо: +67/-0
Offline
Сообщений: 72
|
|
Re: Переменная в потоке
« Ответ #1 : 19 Март 2015, 11:44:08 »
|
|
А параметр JsonMemberNameID для каждого потока свой будет или один на всех?
|
|
|
|
|
|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
Re: Переменная в потоке
« Ответ #2 : 19 Март 2015, 11:49:25 »
|
|
А параметр JsonMemberNameID для каждого потока свой будет или один на всех?
Проблема в том, что параметр должен быть свой для каждого отдельного потока который будет создает IdTCPServer1Execute.
|
|
|
|
|
|
OVE
Участник
Сказали спасибо: +67/-0
Offline
Сообщений: 72
|
|
Re: Переменная в потоке
« Ответ #3 : 19 Март 2015, 11:57:27 »
|
|
Тогда нужно создать структуру типа
struct TTT
{
HANDLE hnd;
String JsonMemberNameID;
}
......
vector tVect;
В качестве nhd указывать уникальный HANDLE потока.
|
|
|
|
|
|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
Re: Переменная в потоке
« Ответ #4 : 19 Март 2015, 12:02:26 »
|
|
Можно поподробнее расписать как это вмонтировать в мой код. Как все будет выглядеть. Где объявлять структуру? Как получить хендл потока?
|
|
|
|
|
|
OVE
Участник
Сказали спасибо: +67/-0
Offline
Сообщений: 72
|
|
Re: Переменная в потоке
« Ответ #5 : 19 Март 2015, 12:19:50 »
|
|
Похоже, можно, сделать проще.
В переменной типа TIdContext, которая передается в OnExecute есть свойство Data. В нем и можно будет запоминать необходимую нам информацию (JsonMemberNameID).
void __fastcall TForm1Main::IdTCPServer1Execute(TIdContext *AContext)
{
//прием данных и затем вызов функции:
String Sdata = AContext->Connection->IOHandler->ReadLn();
ParseJSONValue(AContext,Sdata);
}
Я думаю, должно работать.
//в функции идет разбор json пакета
void ParseJSONValue(TIdContext *AContext,String JsonData)
{
//при первом вызове ParseJSONValue строка JsonData содержит внутри себя нужный параметр.
//после обработки JsonData я этот параметр сохраняю в переменную
if(AContext->Data==NULL)
{ String JsonMemberNameID =тут нужное значение...;
AContext->Data=(TObject*)new String(JsonMemberNameID);
}
//при следующих вызовах ParseJSONValue JsonMemberNameID будет пустым т.к. нужный параметр только в первом пакете
//String JsonMemberNameID =пусто;
//после этого вызывается следующая функция, где JsonMemberNameID передается вторым параметром
ParseJsonArraySens(CoderjimoeJsonArraySens, *(Sting*)AContext->Data);
}
|
|
|
|
|
|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
Re: Переменная в потоке
« Ответ #6 : 19 Март 2015, 12:33:40 »
|
|
Может я не поняла, но вроде работать не будет.
AContext->Data не бывает NULL. Всегда приходят данные. Только в первом пакете данных есть чуть больше чем в следующих. Я из первого пакета данных беру нужное значение. Затем во всех других приходах данных приходит усеченные пакеты. Усеченный пакет приходит всегда во второй-третий-раз и до бесконечности. А вот в самом первом пакете есть нужные данные для JsonMemberNameID + усеченный пакет. Усеченные пакеты нужны и обрабатываются.
А JsonMemberNameID нужен индивидуально для каждого созданного потока...
|
|
|
|
|
|
OVE
Участник
Сказали спасибо: +67/-0
Offline
Сообщений: 72
|
|
Re: Переменная в потоке
« Ответ #7 : 19 Март 2015, 12:55:33 »
|
|
Я сам с инди не работал, но насколько я понял из описания - Data это не данные, а указатель, в который пользователь может заносить какую-то свою информацию.
Data - A user-specified object with values used during execution of the task.
Мне кажется - должно работать.
|
|
|
|
|
|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
Re: Переменная в потоке
« Ответ #8 : 19 Март 2015, 13:37:30 »
|
|
Работает. Вижу нужные данные в базе данных.
Однако при закрытии приложения возникает AV обращения по адрес.
В закрытии формы:
IdTCPServer1->Active = false;
|
|
|
|
|
|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
Re: Переменная в потоке
« Ответ #9 : 19 Март 2015, 13:42:51 »
|
|
Вот тут вроде полезная информация:
http://borland.newsgroups.archived.at/public.delphi.internet.winsock/200804/08041613764.html
но нифига не понятно на паскале.
|
|
|
|
|
|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
Re: Переменная в потоке
« Ответ #10 : 19 Март 2015, 14:10:57 »
|
|
type TMyContext = class(TIdContext) public Description: String; procedure Reset; // anything else you want... end; procedure TForm1.FormCreate(Sender: TObject); begin IdTCPServer1.ContextClass := TMyContext; IdTCPServer1.Active := True; end; procedure TForm1.IdTCPServer1Connect(AContext: TIdContext); begin TMyContext(AContext).Reset; end; procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext); begin TMyContext(AContext).Reset; end; procedure TForm1.IdTCPServer1Execute(AContext: TIdContext); begin TMyContext(AContext).Description := ...; end;
Как это будет на С++?
Что такое procedure Reset? И как будет на С++ TMyContext(AContext).Reset?
Можно это приспособить под мою задачу?
|
|
|
|
|
|
OVE
Участник
Сказали спасибо: +67/-0
Offline
Сообщений: 72
|
|
Re: Переменная в потоке
« Ответ #11 : 19 Март 2015, 14:13:02 »
|
|
Возможно, это происходит из-за того, что мы не чистим Data при закрытии.
Нужно в событии OnDisconnect очистить выделенную под JsonMemberNameID память
void __fastcall TForm1Main::IdTCPServer1OnDisconnect(TIdContext *AContext)
{
if(AContext->Data) delete (String*)AContext->Data;
AContext->Data=NULL;
}
|
|
|
|
|
|
OVE
Участник
Сказали спасибо: +67/-0
Offline
Сообщений: 72
|
|
Re: Переменная в потоке
« Ответ #12 : 19 Март 2015, 14:32:39 »
|
|
1-ый вариант из сылки - это то, что мы и сделали. А во втором - подменяется класс TIdContext на пользовательский.
Что такое procedure Reset? И как будет на С++ TMyContext(AContext).Reset?
Reset - это какая-то пользовательская функция (которая в коде не описана).
((TMyContext*)AContext)->Reset()
|
|
|
|
|
|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
Re: Переменная в потоке
« Ответ #13 : 19 Март 2015, 14:38:02 »
|
|
Огромное спасибо вроде заработало после этого
if(AContext->Data) delete (String*)AContext->Data;
AContext->Data=NULL;
P.S.
А почему тут надо двойной указатель?
ParseJsonArraySens(CoderjimoeJsonArraySens, *(String*)AContext->Data);
|
|
|
|
|
|
OVE
Участник
Сказали спасибо: +67/-0
Offline
Сообщений: 72
|
|
Re: Переменная в потоке
« Ответ #14 : 19 Март 2015, 14:46:16 »
|
|
А почему тут надо двойной указатель?
ParseJsonArraySens(CoderjimoeJsonArraySens, *(String*)AContext->Data);
В AContext->Data по факту у нас находится указатель на строку.
(String*)AContext->Data - это приведение типа к типу "указатель на строку"
А поскольку в функцию мы передаем строку, то нужно сделать разименовывание
*(String*)AContext->Data
|
|
|
|
|
|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
Re: Переменная в потоке
« Ответ #15 : 19 Март 2015, 14:50:53 »
|
|
Большое спасибо за подробные разъяснения и помощь!
P.S.
Оказывается Indy удобная штука.
|
|
|
|
|
|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
Re: Переменная в потоке
« Ответ #16 : 21 Март 2015, 17:24:45 »
|
|
Вот еще такое решение нашлось через класс:
class TMyData : public TObject
{
public:
String Value;
__fastcall TMyData(const String &aValue) : TObject(), Value(aValue) {}
};
void ParseJSONValue(String JsonData, String ServerPascalIP, TIdContext *AContext)
{
//*****
If (AContext->Data == NULL)
{
JsonMemberNameID = JsonMemberValue;
AContext->Data = new TMyData(JsonMemberNameID);
}
//****
ParseJsonArraySens(CoderjimoeJsonArraySens, static_cast(AContext->Data)->Value);
}
void __fastcall TForm1Main::IdTCPServer1Disconnect(TIdContext *AContext)
{
delete AContext->Data;
AContext->Data = NULL;
}
Вопрос такой:
можно ли в AContext->Data иметь, например, два значения и извлекать их оттуда?
|
|
|
|
|
|
S0mbre
Глобальный модератор
Сказали спасибо: +1113/-22
Offline
Сообщений: 2132
S0mbre
|
|
Re: Переменная в потоке
« Ответ #17 : 22 Март 2015, 20:53:44 »
|
|
можно ли в AContext->Data иметь, например, два значения и извлекать их оттуда?
Почему же нет? Хоть сколько переменных, ты же объявляешь пользовательский класс, наследуя от TObject. В этом классе объявляй хоть сколько, хоть какого типа переменные. Можешь даже типа Variant - и приводить их к любым другим типам.
|
|
|
|
|
|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
Re: Переменная в потоке
« Ответ #18 : 23 Март 2015, 09:20:47 »
|
|
Если сделать такое объявление:
class TMyData : public TObject { public: String Value; int count; __fastcall TMyData(const String &aValue) : TObject(), Value(aValue), count(acount) {} }
То надо обращаться так:
String NameID = "..."; int zes = 16; AContext->Data = new TMyData(NameID, zes); //Доступ так: //static_cast(AContext->Data)->count;//int //static_cast(AContext->Data)->Value;//String //**** void __fastcall TForm1Main::IdTCPServer1Disconnect(TIdContext *AContext) { delete AContext->Data; AContext->Data = NULL; }
Правильно?
|
|
|
|
|
|
S0mbre
Глобальный модератор
Сказали спасибо: +1113/-22
Offline
Сообщений: 2132
S0mbre
|
|
Re: Переменная в потоке
« Ответ #19 : 23 Март 2015, 13:42:57 »
|
|
Правильно?
Да. Только в конструкторе TMyData пропустила int acount.
|
|
|
|
|
|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
Re: Переменная в потоке
« Ответ #20 : 23 Март 2015, 14:20:53 »
|
|
Большое спасибо!
|
|
|
|
|
|
SilverFish
Участник
Сказали спасибо: +14/-6
Offline
Сообщений: 786
|
|
« Ответ #21 : 24 Март 2015, 14:46:13 »
|
|
Еще вариант нашелся.
Не требует освобождения AContext->Data
class TMyContext : public TIdServerContext { public: String Value; }; __fastcall TForm1Main::TForm1Main(TComponent *Owner) : TForm(Owner) { IdTCPServer1->ContextClass = __classid(TMyContext); } void ParseJSONValue(String JsonData, String ServerPascalIP, TIdContext *AContext) { TMyContext *Ctx = static_castTMyContext*>(AContext); //**** If (Ctx->Value == "") { JsonMemberNameID = JsonMemberValue; Ctx->Value = JsonMemberNameID; } //**** ParseJsonArraySens(CoderjimoeJsonArraySens, Ctx->Value); }
|
|
|
|
|
|