![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Использование крит.секции [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]> данные главной форме для сохранения в БД
а зачем передавать именно форме?
она еще и отображением их по ходу занимается?