Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Использование крит.секции [D7]


T2k ©   (2009-03-18 15:05:00) 

Есть некоторый класс. Когда я вызываю некоторый метод этого класса, то создается дополнительный поток.
Этот поток работает с девайсом (считывает с него данные). По окончанию обмена я должен передать данные главной форме для сохранения в БД и завершить поток.
Так вот...предположим, что работает сразу несколько доп.потоков (считывают данные) и когда они завершаться я не могу знать. То ли одновременно , то ли по очереди.
Вопрос в следующем, нужна ли критическая секция в главной форме ? По коду,надеюсь, понятней будет


unit Unit1;
...
Obj:=TDial.Create;
Obj.OnData:=ModemData;

...
procedure TForm1.ModemData(CashID,Mode,TaskID,Res: DWord; ThreadObj: TObjectList);
begin
  EnterCriticalSection(CS); // ???
 // сохраняю данные в БД
  LeaveCriticalSection(CS); // ???
end;

unit DialUnit;

type
 TOnData  = procedure(CashID,Mode,TaskID,Res:DWord;ThreadObj:TObjectList) of object;

type
 TDial = class(TObject)
private
 FOnData:TOnData;
 ...
public
  procedure DoData(CashID,Mode,TaskID,Res:DWord;ThreadObj:TObjectList);
end;

procedure TDial.DoData(CashID,Mode,TaskID,Res: DWord; ThreadObj: TObjectList);
begin
 if Assigned(FOnData) then OnData(CashID,Mode,TaskID,Res,ThreadObj);
end;

//доп.поток
function TDial.FDeviceThread(...)
begin
 // получаю данные с девайса
  DoData(CashID,Mode,TaskID,Y,Obj); // выгрузить данные в главн.форму
end;


Сергей М.   (2009-03-18 20:30:00) [1]


> Прямо из доп.потока сохранять данные в БД


> или как-то (сообщением или еще как) отправить данные из
> доп.потока главному и там(в главном) сохранять ?


Оба варианта имеют право на жизнь, выбирать тебе.
Хочу лишь заметить, что второй вариант - это как раз то что ты хотел добиться с пом. КС в изначальном вопросе.


T2k   (2009-03-18 18:44:00) [2]

2 Сергей М. ©   (18.03.09 17:58) [9]

Спасибо. Теперь вроде понятно. Только опять таки вопрос...как правильно подойти к моей задаче ? Прямо из доп.потока сохранять данные в БД или как-то (сообщением или еще как) отправить данные из доп.потока главному и там(в главном) сохранять ?

2  clickmaker ©   (18.03.09 18:19) [10]

Спасибо, понял. Вот бы еще примерчик...как из потока работать с БД ;)
Хотя поищу...может что в инете есть.


clickmaker   (2009-03-18 18:19:00) [3]

> [6] T2k   (18.03.09 17:34)
>
> 2 clickmaker ©   (18.03.09 17:22) [4]
> > используй DataModule тогда
>
> Хорошо. Я посмотрю в эту сторону. Но а чем мой вариант плох
> ???

во-первых, при наличии большого числа компонентов БД на форме, ты в один прекрасный момент не сможешь раскопать визуальные, которые окажутся под ними.
ну а во-вторых - нормальное и логичное желание отделять работу с БД от интерфейса. Это не кажется актуальным, когда у тебя 2-3 эдита и один кверик, но на более серьезном проекте преимущества будут налицо, поверь


Сергей М.   (2009-03-18 17:58:00) [4]


> Далее вызывается событие  DoData, код которого расположен
> в unit1.pas


Так ведь в unit1 расположен код, а не кодовый поток(тред) !

В том-то и весь смысл мультипоточности, что один и тот же участок кода может быть вызван и исполняться одновременно в контексте более чем одного треда ..

В дан.случае тело проц-ры DoData будет исполнено в том жепотоке, в котором эта процедура была вызвана.


T2k   (2009-03-18 17:40:00) [5]

2 Сергей М. ©   (18.03.09 17:36) [7]

Ну как в [0].
Работает доп.поток, накапливает данные в TObjectList. Далее вызывается событие  DoData, код которого расположен в unit1.pas. Разве я не прав ?


Сергей М.   (2009-03-18 17:36:00) [6]


> У меня все доп.потоки передают данные главному


Гдеэто видно из приведенного кода ?
Я этого не вижу, приведи цитату ..


T2k   (2009-03-18 17:34:00) [7]

2 Сергей М. ©   (18.03.09 17:24) [5]
FB требует как минимум отдельное соединение (отдельный объект TIBDatabase) на каждый тред, использующий это соединение для последующего доступа к объектам БД.

Погодите...У меня все доп.потоки передают данные главному. А из главного я и работаю с БД. Повторюсь...главные поток(читай Unit1.pas) работает c БД. Что не так ?

2 clickmaker ©   (18.03.09 17:22) [4]
> используй DataModule тогда

Хорошо. Я посмотрю в эту сторону. Но а чем мой вариант плох ???


Сергей М.   (2009-03-18 17:24:00) [8]


> T2k   (18.03.09 17:17) [3]


FB требует как минимум отдельноесоединение (отдельный объект TIBDatabase) на каждый тред, использующий это соединение для последующего доступа к объектам БД.

Этот требование тобой, похоже, не выполняется, так что дальнейший разговор про КС пока лишен смысла


clickmaker   (2009-03-18 17:22:00) [9]

> [3] T2k   (18.03.09 17:17)
> 2 clickmaker ©   (18.03.09 15:49) [1]
>
> Ну...не знаю. Я так сам решил. Ибо не знаю, как работать
> с БД из потока.
> Мне проще с компонентами работать при работе с БД.

используй DataModule тогда


T2k   (2009-03-18 17:17:00) [10]

2 clickmaker ©   (18.03.09 15:49) [1]

Ну...не знаю. Я так сам решил. Ибо не знаю, как работать с БД из потока.
Мне проще с компонентами работать при работе с БД.

>она еще и отображением их по ходу занимается?
Нет. Только сохранение в БД и все. Отображение на другой программе.

2 Сергей М. ©   (18.03.09 16:08) [2]
> Решение зависит от того, что скрывается за

FireBird. Запись данных в пару таблиц. Код показать ?
Ну вот, например основной кусок :

...
ObjList.Clear;
   for I:=0 to ThreadObj.Count-1 do
   begin
     ObjList.Add(TStringList.Create);
     TStrings(ObjList.Items[I]).AddStrings(TStrings(ThreadObj.Items[I]));
   end;
   //
   Transact;
   IBSQL1.Close;
   IBSQL1.SQL.Clear;
   case Mode of
     0:begin   // товары
         IBSQL1.SQL.Add('DELETE FROM PLUREAD WHERE CASHID=:ID');
         IBSQL1.ParamByName('ID').AsInt64:=CashID;
         IBSQL1.ExecQuery;
       end;
     1:begin  // за день
         IBSQL1.SQL.Add('DELETE FROM DAYSALES WHERE CASHID=:ID AND DAYSALE=:DAY');
         IBSQL1.ParamByName('ID').AsInt64:=CashID;
         IBSQL1.ParamByName('DAY').AsDate:=Now;
         IBSQL1.ExecQuery;
       end;
     2:begin // с накоплением
         IBSQL1.SQL.Add('DELETE FROM DAYSALESTIME WHERE CASHID=:ID AND DAYSALE=:DAY');
         IBSQL1.ParamByName('ID').AsInt64:=CashID;
         IBSQL1.ParamByName('DAY').AsDate:=Now;
         IBSQL1.ExecQuery;
       end;
     3:begin  // нулевые остатки
         IBSQL1.SQL.Add('DELETE FROM ZEROPLU WHERE CASHID=:ID');
         IBSQL1.ParamByName('ID').AsInt64:=CashID;
         IBSQL1.ExecQuery;
       end;
     6:begin // начало/конец раб.дня
         if TStrings(ObjList.Items[0]).Count>0 then
         begin
           Memo1.Lines.Add('');
           Memo1.Lines.Add('Начало рабочего дня: '+TStrings(ObjList.Items[0]).Strings[0]);
           Memo1.Lines.Add('Конец рабочего дня: '+TStrings(ObjList.Items[0]).Strings[1]);
           Memo1.Lines.Add('');
         end;
       end;
     4:begin //запись
         if ObjList.Count>0 then
         begin
           for I:=0 to TStrings(ObjList.Items[0]).Count-1 do
           begin
             if TStrings(ObjList.Items[7]).Strings[I]='0' then
             begin
               if TryStrToInt(TStrings(ObjList.Items[8]).Strings[I],hInt) then
               begin
                 IBSQL1.Close;
                 IBSQL1.SQL.Clear;
                 IBSQL1.SQL.Add('DELETE FROM PLUWRITE WHERE ID=:HID');
                 IBSQL1.ParamByName('HID').AsInteger:=hInt;
                 IBSQL1.ExecQuery;
               end;
             end else
             begin
               if TryStrToInt(TStrings(ObjList.Items[8]).Strings[I],hInt) then
               begin
                 IBSQL1.Close;
                 IBSQL1.SQL.Clear;
                 IBSQL1.SQL.Add('UPDATE PLUWRITE SET TEXTERROR=:HTEXT WHERE ID=:HID');
                 IBSQL1.ParamByName('HID').AsInteger:=hInt;
                 if TryStrToInt(TStrings(ObjList.Items[7]).Strings[I],hTemp) then
                  IBSQL1.ParamByName('HTEXT').AsString:=GetDeviceError(hTemp) else
                   IBSQL1.ParamByName('HTEXT').AsString:='глобальная ошибка';
                 IBSQL1.ExecQuery;
               end;
             end;  
           end;
         end;
       end;

   end; // end case
   TransactCommit;
   Transact;
   //
   //SaveLog(' First Transact  Касса:'+IntToStr(CashID));
   // запись
   case Mode of
   1:begin // продажи за день
       for I:=0 to TStrings(ObjList.Items[0]).Count-1 do
       begin
         IBSQL1.SQL.Clear;
         //
         if STCIstokMode=0 then
         begin // обычная версия
           IBSQL1.SQL.Add('INSERT INTO DAYSALES VALUES(GEN_ID(IDDAYSALES,1),');
           IBSQL1.SQL.Add(':DAY,:CASH,:CODE,:NAME,:PRICE,:AMOUNT,:GRP,:TAX,:NSALE,:SSALE,:N PAY,:SPAY)');
         end;
         if STCIstokMode=1 then
         begin    // версия для Одессы
           IBSQL1.SQL.Add('INSERT INTO DAYSALES VALUES(GEN_ID(IDDAYSALES,1),:TASK,');
           IBSQL1.SQL.Add(':DAY,:CASH,:CODE,:NAME,:PRICE,:AMOUNT,:GRP,:TAX,:NSALE,:SSALE,:N PAY,:SPAY)');
           IBSQL1.ParamByName('TASK').AsInteger:=TaskID;
         end;
         //
         IBSQL1.ParamByName('DAY').AsDate:=Now;
         IBSQL1.ParamByName('CASH').AsInt64:=CashID;
         if not TryStrToInt64(TStrings(ObjList.Items[0]).Strings[I],hInt64) then hInt64:=0;
         IBSQL1.ParamByName('CODE').AsInt64:=hInt64;
         if Length(TStrings(ObjList.Items[1]).Strings[I])=0 then
          IBSQL1.ParamByName('NAME').Value:=null else
           begin
             hSt:= TStrings(ObjList.Items[1]).Strings[I];
             if Length(hSt)>25 then hSt:=Copy(hSt,1,25);
             IBSQL1.ParamByName('NAME').Value:=hSt;
           end;
         if not TryStrToFloat(TStrings(ObjList.Items[2]).Strings[I],hExt) then hExt:=0;
         IBSQL1.ParamByName('PRICE').AsFloat:=hExt;
         if not TryStrToFloat(TStrings(ObjList.Items[3]).Strings[I],hExt) then hExt:=0;
         IBSQL1.ParamByName('AMOUNT').AsFloat:=hExt;
         if not TryStrToInt(TStrings(ObjList.Items[6]).Strings[I],hInt) then hInt:=0;
         IBSQL1.ParamByName('GRP').AsInteger:=hInt;
         if not TryStrToInt(TStrings(ObjList.Items[7]).Strings[I],hInt) then hInt:=0;
         IBSQL1.ParamByName('TAX').AsInteger:=hInt;
         if not TryStrToFloat(TStrings(ObjList.Items[4]).Strings[I],hExt) then hExt:=0;
         IBSQL1.ParamByName('NSALE').AsFloat:=hExt;
         if not TryStrToFloat(TStrings(ObjList.Items[5]).Strings[I],hExt) then hExt:=0;
         IBSQL1.ParamByName('SSALE').AsFloat:=hExt;
         if not TryStrToFloat(TStrings(ObjList.Items[8]).Strings[I],hExt) then hExt:=0;
         IBSQL1.ParamByName('NPAY').AsFloat:=hExt;
         if not TryStrToFloat(TStrings(ObjList.Items[9]).Strings[I],hExt) then hExt:=0;
         IBSQL1.ParamByName('SPAY').AsFloat:=hExt;
         //
         IBSQL1.ExecQuery;
       end;
     end;


Сергей М.   (2009-03-18 16:08:00) [11]

Решение зависит от того, что скрывается за

> // сохраняю данные в БД


clickmaker   (2009-03-18 15:49:00) [12]

> данные главной форме для сохранения в БД

а зачем передавать именно форме?
она еще и отображением их по ходу занимается?


Наверх

Титульная страница Поиск, карта сайта Написать письмо