R
Richard3000
Unregistered / Unconfirmed
GUEST, unregistred user!
目前的问题:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1663196
[red]一台PC以令牌的方式用RS232访问30-50台电子秤,从电子秤读来的数据必须先存到内存里,
然后再把内存中的数据写到数据库中。[/red]
[blue]我的想法是写两个线程,一个负责从电子秤读数据并保存到一个队列里,另一个线程负责把
队列中的数据写到数据库中。不知道这种做法合适吗?有没有更好的办法?[/blue]
各位大哥能不能留下MSN?我的是 mailto:zhenhuazhao@hotmail.com
目前的代码(没有一个数据能存到数据库中[],关闭时出错[!]):
unit UntMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,ADODB,Contnrs, DB, StdCtrls;
const
MAX_BALANCE_COUNT=100;
//电子秤的最大数量(电子秤秤号为2位ASCII码)
MAX_UNSAVE_COUNT=2000;
//不能写入数据库的数据的最大数,大约有3分钟的数据
type
TBalance=class
private
BalanID:String[2];//秤号:2位ASCII码
SerialID:String;//流水号:5位ASCII码
Weightouble;//重量
WriteTimeouble;//最后一次访问时间
PowerOn:Boolean;
Saved:Boolean;
public
constructor Create;
end;
TReadBalance=class(TThread)
private
ADOQuery:TADOQuery;
protected
procedure Execute;override;
procedure InitBalance;
public
constructor Create(aADOQuery:TADOQuery);
end;
TWriteBalance=class(TThread)
private
ADOQuery:TADOQuery;
function SaveToDatabase(Balance:TBalance):Boolean;
protected
procedure Execute;override;
public
constructor Create(aADOQuery:TADOQuery);
end;
TFrmMain = class(TForm)
ADOConnection1: TADOConnection;
ADOQuery1: TADOQuery;
ADOQuery2: TADOQuery;
btnStart: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btnStartClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FrmMain: TFrmMain;
implementation
{$R *.dfm}
var
hSem:THandle=0;
BalanceQueue:TObjectQueue;//队列,用于保存从电子秤读来的数据
Balances:array [0..MAX_BALANCE_COUNT-1] of TBalance;//电子秤数据
UnsavedCount:Integer=0;//用于记录从队列中读出数据但是写不到数据库的个数
ReadBalance:TReadBalance;
WriteBalance:TWriteBalance;
ReadCount:Integer;
constructor TBalance.Create;
begin
Saved:=False;
end;
constructor TReadBalance.Create(aADOQuery:TADOQuery);
begin
ADOQuery:=aADOQuery;
inherited Create(False);
end;
constructor TWriteBalance.Create(aADOQuery:TADOQuery);
begin
ADOQuery:=aADOQuery;
inherited Create(False);
end;
procedure TReadBalance.InitBalance;
var
Balance:TBalance;
i:Integer;
begin
try
with ADOQuerydo
begin
if Active then
Close;
SQL.Clear;
SQL.Add('SELECT BalanceID,WorkState FROM Balances');
Open;
First;
if WaitForSingleObject(hSem,INFINITE)=WAIT_OBJECT_0 then
for i:=Low(Balances) to High(Balances)do
begin
{if Balances.PowerOn then
begin
Next;
Continue;
end;
//if Balances<>nil then
}
Balance:=TBalance.Create;
Balance.PowerOn:=FieldByName('WorkState').AsBoolean;
Balance.Saved:=False;
Balance.BalanID:=FieldByName('BalanceID').AsString;
Balances:=Balance;
Next;
end;
//while not Eofdo
ReleaseSemaphore(hSem,1,nil);
end;
//with ADOQuerydo
except
Abort;
end;
end;
procedure TReadBalance.Execute;
var
Balance:TBalance;
i:Integer;
begin
FreeOnTerminate:=True;
while not Terminateddo
begin
if (ReadCount mod 10000000)=0 then
//每读10000000次,初始化一次电子秤状态
begin
ReadCount:=1;
InitBalance;
//if ReadCount>=100 then
end;
if WaitForSingleObject(hSem,INFINITE)=WAIT_OBJECT_0 then
for i:=Low(Balances) to High(Balances)do
begin
if not Balances.PowerOn then
//没有通电
Continue;
if ((Random(7) mod 2)<>0) then
//假设此时读不到数据
Continue;
Inc(ReadCount);
Balance:=TBalance.Create;
with Balancedo
begin
WriteTime:=Now;
if i<10 then
BalanID:='0'+IntToStr(i)
else
BalanID:=IntToStr(i);
//if i<10 then
SerialID:=Copy(IntToStr(GetTickCount()),1,5);
Weight:=Random(300);
end;
//with Balancedo
Balances:=Balance;
BalanceQueue.Push(Balance);
//压入链表当中
Inc(ReadCount);
end;
ReleaseSemaphore(hSem,1,nil);
end;
end;
function TWriteBalance.SaveToDatabase(Balance:TBalance):Boolean;
begin
try
with ADOQuerydo
begin
if Active then
Close;
SQL.Clear;
SQL.Add('INSERT INTO SaveData (BalanceID,Serial,WriteTime)');
SQL.Add(' VALUES BalanceID,:Serial,:WriteTime)');
Parameters.ParamByName('BalanceID').Value:=Balance.BalanID;
Parameters.ParamByName('Serial').Value:=Balance.SerialID;
Parameters.ParamByName('WriteTime').Value:=Balance.WriteTime;
ExecSQL;
end;
Result:=True;
except
Result:=False;
end;
end;
procedure TWriteBalance.Execute;
var
Balance:TBalance;
Index:Integer;
begin
FreeOnTerminate:=True;
while not Terminateddo
begin
if BalanceQueue.Count>0 then
//队列有数据
begin
if WaitForSingleObject(hSem,INFINITE)=WAIT_OBJECT_0 then
begin
Balance:=TBalance(BalanceQueue.Pop);
if SaveToDatabase(Balance) then
begin
Index:=StrToInt(Balance.BalanID);
Balances[Index].Saved:=True;
end else
begin
BalanceQueue.Push(Balance);
Inc(UnsavedCount);
end;
//if SaveToDatabase(Balance) then
end;
//if WaitForSingleObject(hSem,INFINITE)=WAIT_OBJECT_0 then
ReleaseSemaphore(hSem,1,nil);
end;
end;
end;
procedure TFrmMain.FormCreate(Sender: TObject);
begin
hSem:=CreateSemaphore(nil,0,3,nil);//[red]hSem:=CreateSemaphore(nil,3,30,nil);时有12条数据被保存[/red]
BalanceQueue:=TObjectQueue.Create;
end;
procedure TFrmMain.FormDestroy(Sender: TObject);
begin
BalanceQueue.Free;
CloseHandle(hSem);
end;
procedure TFrmMain.btnStartClick(Sender: TObject);
begin
ReadBalance:=TReadBalance.Create(ADOQuery1);
WriteBalance:=TWriteBalance.Create(ADOQuery2);
end;
end.
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1663196
[red]一台PC以令牌的方式用RS232访问30-50台电子秤,从电子秤读来的数据必须先存到内存里,
然后再把内存中的数据写到数据库中。[/red]
[blue]我的想法是写两个线程,一个负责从电子秤读数据并保存到一个队列里,另一个线程负责把
队列中的数据写到数据库中。不知道这种做法合适吗?有没有更好的办法?[/blue]
各位大哥能不能留下MSN?我的是 mailto:zhenhuazhao@hotmail.com
目前的代码(没有一个数据能存到数据库中[],关闭时出错[!]):
unit UntMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,ADODB,Contnrs, DB, StdCtrls;
const
MAX_BALANCE_COUNT=100;
//电子秤的最大数量(电子秤秤号为2位ASCII码)
MAX_UNSAVE_COUNT=2000;
//不能写入数据库的数据的最大数,大约有3分钟的数据
type
TBalance=class
private
BalanID:String[2];//秤号:2位ASCII码
SerialID:String;//流水号:5位ASCII码
Weightouble;//重量
WriteTimeouble;//最后一次访问时间
PowerOn:Boolean;
Saved:Boolean;
public
constructor Create;
end;
TReadBalance=class(TThread)
private
ADOQuery:TADOQuery;
protected
procedure Execute;override;
procedure InitBalance;
public
constructor Create(aADOQuery:TADOQuery);
end;
TWriteBalance=class(TThread)
private
ADOQuery:TADOQuery;
function SaveToDatabase(Balance:TBalance):Boolean;
protected
procedure Execute;override;
public
constructor Create(aADOQuery:TADOQuery);
end;
TFrmMain = class(TForm)
ADOConnection1: TADOConnection;
ADOQuery1: TADOQuery;
ADOQuery2: TADOQuery;
btnStart: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btnStartClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FrmMain: TFrmMain;
implementation
{$R *.dfm}
var
hSem:THandle=0;
BalanceQueue:TObjectQueue;//队列,用于保存从电子秤读来的数据
Balances:array [0..MAX_BALANCE_COUNT-1] of TBalance;//电子秤数据
UnsavedCount:Integer=0;//用于记录从队列中读出数据但是写不到数据库的个数
ReadBalance:TReadBalance;
WriteBalance:TWriteBalance;
ReadCount:Integer;
constructor TBalance.Create;
begin
Saved:=False;
end;
constructor TReadBalance.Create(aADOQuery:TADOQuery);
begin
ADOQuery:=aADOQuery;
inherited Create(False);
end;
constructor TWriteBalance.Create(aADOQuery:TADOQuery);
begin
ADOQuery:=aADOQuery;
inherited Create(False);
end;
procedure TReadBalance.InitBalance;
var
Balance:TBalance;
i:Integer;
begin
try
with ADOQuerydo
begin
if Active then
Close;
SQL.Clear;
SQL.Add('SELECT BalanceID,WorkState FROM Balances');
Open;
First;
if WaitForSingleObject(hSem,INFINITE)=WAIT_OBJECT_0 then
for i:=Low(Balances) to High(Balances)do
begin
{if Balances.PowerOn then
begin
Next;
Continue;
end;
//if Balances<>nil then
}
Balance:=TBalance.Create;
Balance.PowerOn:=FieldByName('WorkState').AsBoolean;
Balance.Saved:=False;
Balance.BalanID:=FieldByName('BalanceID').AsString;
Balances:=Balance;
Next;
end;
//while not Eofdo
ReleaseSemaphore(hSem,1,nil);
end;
//with ADOQuerydo
except
Abort;
end;
end;
procedure TReadBalance.Execute;
var
Balance:TBalance;
i:Integer;
begin
FreeOnTerminate:=True;
while not Terminateddo
begin
if (ReadCount mod 10000000)=0 then
//每读10000000次,初始化一次电子秤状态
begin
ReadCount:=1;
InitBalance;
//if ReadCount>=100 then
end;
if WaitForSingleObject(hSem,INFINITE)=WAIT_OBJECT_0 then
for i:=Low(Balances) to High(Balances)do
begin
if not Balances.PowerOn then
//没有通电
Continue;
if ((Random(7) mod 2)<>0) then
//假设此时读不到数据
Continue;
Inc(ReadCount);
Balance:=TBalance.Create;
with Balancedo
begin
WriteTime:=Now;
if i<10 then
BalanID:='0'+IntToStr(i)
else
BalanID:=IntToStr(i);
//if i<10 then
SerialID:=Copy(IntToStr(GetTickCount()),1,5);
Weight:=Random(300);
end;
//with Balancedo
Balances:=Balance;
BalanceQueue.Push(Balance);
//压入链表当中
Inc(ReadCount);
end;
ReleaseSemaphore(hSem,1,nil);
end;
end;
function TWriteBalance.SaveToDatabase(Balance:TBalance):Boolean;
begin
try
with ADOQuerydo
begin
if Active then
Close;
SQL.Clear;
SQL.Add('INSERT INTO SaveData (BalanceID,Serial,WriteTime)');
SQL.Add(' VALUES BalanceID,:Serial,:WriteTime)');
Parameters.ParamByName('BalanceID').Value:=Balance.BalanID;
Parameters.ParamByName('Serial').Value:=Balance.SerialID;
Parameters.ParamByName('WriteTime').Value:=Balance.WriteTime;
ExecSQL;
end;
Result:=True;
except
Result:=False;
end;
end;
procedure TWriteBalance.Execute;
var
Balance:TBalance;
Index:Integer;
begin
FreeOnTerminate:=True;
while not Terminateddo
begin
if BalanceQueue.Count>0 then
//队列有数据
begin
if WaitForSingleObject(hSem,INFINITE)=WAIT_OBJECT_0 then
begin
Balance:=TBalance(BalanceQueue.Pop);
if SaveToDatabase(Balance) then
begin
Index:=StrToInt(Balance.BalanID);
Balances[Index].Saved:=True;
end else
begin
BalanceQueue.Push(Balance);
Inc(UnsavedCount);
end;
//if SaveToDatabase(Balance) then
end;
//if WaitForSingleObject(hSem,INFINITE)=WAIT_OBJECT_0 then
ReleaseSemaphore(hSem,1,nil);
end;
end;
end;
procedure TFrmMain.FormCreate(Sender: TObject);
begin
hSem:=CreateSemaphore(nil,0,3,nil);//[red]hSem:=CreateSemaphore(nil,3,30,nil);时有12条数据被保存[/red]
BalanceQueue:=TObjectQueue.Create;
end;
procedure TFrmMain.FormDestroy(Sender: TObject);
begin
BalanceQueue.Free;
CloseHandle(hSem);
end;
procedure TFrmMain.btnStartClick(Sender: TObject);
begin
ReadBalance:=TReadBalance.Create(ADOQuery1);
WriteBalance:=TWriteBalance.Create(ADOQuery2);
end;
end.