C++Builder
  Начало   Форум   Помощь Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Переменная в потоке  (Прочитано 2970 раз)
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 »

Цитата: SilverFish от 21 Март 2015, 17:24:45
можно ли в 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 »

Цитата: SilverFish от 23 Март 2015, 09:20:47
Правильно?

Да. Только в конструкторе 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);
   }
 
 
 
 
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  




....

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