你的代码出了些问题。我为这种情况准备了一个测试应用程序,因为我将在几天内在多线程环境中面对TClientDataSet。我的测试案例应用程序没有出现这个问题(Delphi 2010更新5)
我将在几天后在自己的博客中发布这个代码...目前我给了你:
DFM文件:
object Form2: TForm2
Left = 0
Top = 0
Caption = 'Form2'
ClientHeight = 337
ClientWidth = 635
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnClose = FormClose
PixelsPerInch = 96
TextHeight = 13
object Memo1: TMemo
Left = 8
Top = 8
Width = 257
Height = 321
Lines.Strings = (
'Memo1')
TabOrder = 0
end
object Button1: TButton
Left = 271
Top = 8
Width = 170
Height = 25
Caption = 'Start'
TabOrder = 1
OnClick = Button1Click
end
object cdsTest: TClientDataSet
Aggregates = <>
Params = <>
Left = 584
Top = 32
object cdsTestNumber: TIntegerField
FieldName = 'Number'
end
end
object tToMemo: TTimer
Enabled = False
Interval = 500
OnTimer = tToMemoTimer
Left = 376
Top = 144
end
end
pas文件:
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, DBClient, SyncObjs, ExtCtrls;
type
TWriterThread = class(TThread)
private
FDataSet: TClientDataSet;
FLock: TCriticalSection;
public
constructor Create(ADataSet: TClientDataSet; ALock: TCriticalSection);
procedure Execute; override;
end;
TDeleterThread = class(TThread)
private
FDataSet: TClientDataSet;
FLock: TCriticalSection;
public
constructor Create(ADataSet: TClientDataSet; ALock: TCriticalSection);
procedure Execute; override;
end;
TForm2 = class(TForm)
cdsTest: TClientDataSet;
Memo1: TMemo;
cdsTestNumber: TIntegerField;
Button1: TButton;
tToMemo: TTimer;
procedure Button1Click(Sender: TObject);
procedure tToMemoTimer(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
FLock: TCriticalSection;
FWriterThread: TWriterThread;
FDeleterThread: TDeleterThread;
procedure cdsToMemo;
public
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
begin
Button1.Enabled := False;
cdsTest.CreateDataSet;
cdsTest.LogChanges := False;
FLock := TCriticalSection.Create;
tToMemo.Enabled := True;
FWriterThread := TWriterThread.Create(cdsTest, FLock);
FDeleterThread := TDeleterThread.Create(cdsTest, FLock);
end;
constructor TWriterThread.Create(ADataSet: TClientDataSet;
ALock: TCriticalSection);
begin
inherited Create(False);
FDataSet := ADataSet;
FLock := ALock;
end;
procedure TWriterThread.Execute;
var
I: Integer;
begin
inherited;
I := 0;
while not Terminated do
begin
FLock.Enter;
try
Inc(I);
FDataSet.AppendRecord([I]);
finally
FLock.Leave;
end;
Sleep(500);
end;
end;
constructor TDeleterThread.Create(ADataSet: TClientDataSet;
ALock: TCriticalSection);
begin
inherited Create(False);
FDataSet := ADataSet;
FLock := ALock;
end;
procedure TDeleterThread.Execute;
const
MaxRecords = 100;
var
ProcessedRecords: Integer;
begin
inherited;
while not Terminated do
begin
Sleep(3000);
FLock.Enter;
try
FDataSet.First;
ProcessedRecords := 0;
while (not FDataSet.Eof) and (ProcessedRecords < MaxRecords) do
begin
Inc(ProcessedRecords);
if Odd(FDataSet.Fields[0].AsInteger) then
FDataSet.Delete
else
FDataSet.Next;
end;
finally
FLock.Leave;
end;
end;
end;
procedure TForm2.cdsToMemo;
begin
FLock.Enter;
try
Memo1.Lines.BeginUpdate;
try
Memo1.Lines.Clear;
cdsTest.First;
while not cdsTest.Eof do
begin
Memo1.Lines.Add(cdsTestNumber.AsString);
cdsTest.Next;
end;
finally
Memo1.Lines.EndUpdate;
end;
finally
FLock.Leave;
end;
end;
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
tToMemo.Enabled := False;
if cdsTest.Active then
begin
FDeleterThread.Terminate;
FDeleterThread.WaitFor;
FWriterThread.Terminate;
FWriterThread.WaitFor;
end;
end;
procedure TForm2.tToMemoTimer(Sender: TObject);
begin
tToMemo.Enabled := False;
cdsToMemo;
tToMemo.Enabled := True;
end;
end.
我不会再发更多的解释了,因为您似乎对多线程编程很熟悉。如果您有任何疑问,请随时在评论中提出。
只有一件事...我原本计划使用TMultiReadExclusiveWriteSynchronizer来实现更好的并发性,但我没有将ReadAccess提升为WriteAccess的经验,因此使用了CriticalSection来避免现在需要调查的时间。