在我的应用程序中,当我编写文本文件(日志、跟踪等)时,我使用TFileStream
class. 在某些情况下,我在多线程环境中编写数据,这些是步骤:
1- 写入缓存数据
2- 对于我保存到文件的每 1000 行。
3-清除数据。
在所有处理过程中重复此过程。
问题描述:
对于 16 个线程,系统会抛出以下异常:
访问冲突 - 文件已被另一个应用程序使用。
我猜这是因为当另一个线程需要打开时,一个线程使用的句柄尚未关闭。
我将架构更改为以下内容:(下面是新的实现)
在以前的方式中,TFileStream 是使用 FileName 和 Mode 参数创建的,并在关闭句柄时销毁(我没有使用 TMyFileStream)
TMyFileStream = class(TFileStream)
public
destructor Destroy; override;
end;
TLog = class(TStringList)
private
FFileHandle: Integer;
FirstTime: Boolean;
FName: String;
protected
procedure Flush;
constructor Create;
destructor Destroy;
end;
destructor TMyFileStream.Destroy;
begin
//Do Not Close the Handle, yet!
FHandle := -1;
inherited Destroy;
end;
procedure TLog.Flush;
var
StrBuf: PChar; LogFile: string;
F: TFileStream;
InternalHandle: Cardinal;
begin
if (Text <> '') then
begin
LogFile:= GetDir() + FName + '.txt';
ForceDirectories(ExtractFilePath(LogFile));
if FFileHandle < 0 then
begin
if FirstTime then
FirstTime := False;
if FileExists(LogFile) then
if not SysUtils.DeleteFile(LogFile) then
RaiseLastOSError;
InternalHandle := CreateFile(PChar(LogFile), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_NEW, 0,0);
if InternalHandle = INVALID_HANDLE_VALUE then
RaiseLastOSError
else if GetLastError = ERROR_ALREADY_EXISTS then
begin
InternalHandle := CreateFile(PChar(LogFile), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, nil, OPEN_EXISTING, 0,0);
if InternalHandle = INVALID_HANDLE_VALUE then
RaiseLastOSError
else
FFileHandle := InternalHandle;
end
else
FFileHandle := InternalHandle;
end;
F := TMyFileStream.Create(FFileHandle);
try
StrBuf := PChar(Text);
F.Position := F.Size;
F.Write(StrBuf^, StrLen(StrBuf));
finally
F.Free();
end;
Clear;
end;
end;
destructor TLog.Destroy;
begin
FUserList:= nil;
Flush;
if FFileHandle >= 0 then
CloseHandle(FFileHandle);
inherited;
end;
constructor TLog.Create;
begin
inherited;
FirstTime := True;
FFileHandle := -1;
end;
还有另一种更好的方法吗?
这个实现正确吗?
我可以改进这个吗?
我对 Handle 的猜测是对的?
所有 theads 都使用相同的 Log 对象。
没有重入,我检查了!TFileStream 有问题。
对 Add 的访问是同步的,我的意思是,我使用了关键会话,当它达到 1000 行时,调用 Flush 过程。
PS:我不想要第三方组件,我想创建自己的。