Vodnik писал(а):Но позвольте спросить: почему тогда работает классическая запись в файл?
Посмотри внутренности TStrings.SaveToFile и далее.
При AssignFile, Append и Writeln файл не перезаписывается, а добавляются к нему записи.
Код: Выделить всё
Str.LoadFromFile('SomeFile.txt');
Str.Add('Hello');
Str.SaveToFile('SomeFile.txt');
Допустим, несколько потоков загрузили файл и начали его сохранять. Даже если одновременного доступа на запись к файлу не было, то всё равно там окажутся данные последнего завершившегося потока.
Добавлено спустя 17 минут 25 секунд:Короче вот набросал пример.
Потокобезопасная библиотека:), т.е. доступ к файлу будет только у одного потока, остальные будут ждать на EnterCriticalSection(CriticalSection);
Общий юнит:
Код: Выделить всё
unit ufilesafe;
{$mode objfpc}{$H+}
interface
{$IFNDEF BUILD_LIB}
const
libname = 'filesafe';
{$ENDIF}
procedure my_operation(const worklog: PChar); cdecl;{$IFNDEF BUILD_LIB} external libname;{$ENDIF}
implementation
{$IFDEF BUILD_LIB}// <== defined in Project Parameters->User Parameters.
uses
Classes,
SysUtils;
var
CriticalSection: TRTLCriticalSection;
procedure my_operation(const worklog: PChar); cdecl;
var
Stream: TFileStream;
Mode: Word;
List: TStringList;
// temp: string;
begin
EnterCriticalSection(CriticalSection);
try
// temp:=Utf8ToAnsi(worklog);
if FileExists(worklog) then
Mode := fmOpenReadWrite
else
Mode := fmCreate;
Stream := TFileStream.Create(worklog, Mode);
try
List := TStringList.Create;
try
// if Stream.Size > 0 then
// List.LoadFromStream(Stream);
{********************* Work area ************************}
List.Add('growth ' + IntToStr(Stream.Size));
{********************************************************}
Stream.Seek(0, soEnd);
List.SaveToStream(Stream);
finally
List.Free;
end;
finally
Stream.Free;
end;
finally
LeaveCriticalSection(CriticalSection);
end;
end;
initialization
InitCriticalSection(CriticalSection);
finalization
DoneCriticalSection(CriticalSection);
{$ENDIF}
end.
библиотека:
Код: Выделить всё
library libfilesafe;
{$LIBPREFIX ''}
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
ufilesafe;
exports
my_operation;
begin
end.
Программа:
Код: Выделить всё
program filesafe;
{$mode objfpc}{$H+}
{$IFDEF WINDOWS}
{$APPTYPE CONSOLE}
{$ENDIF}
uses
{$IFDEF UNIX}
cthreads,
cwstring,
{$ENDIF}
SysUtils,
ufilesafe;
const
threadcount = 10;
var
finished: LongInt;
function f(p: pointer): PtrInt;
begin
Writeln('thread ', threadId, ' started');
my_operation(PChar(p));
Writeln('thread ', threadId, ' finished');
InterLockedIncrement(finished);
Result := 0;
end;
procedure test(const FileName: string);
var
I: Integer;
Temp: string;
begin
finished := 0;
Temp := Utf8ToAnsi(FileName);
for i := 1 to threadcount do
BeginThread(@f, Pointer(Temp));
while finished < threadcount do ;
Writeln(finished);
finished := 0;
end;
begin
test(GetTempDir(True) + 'workarea.txt');
test(GetTempDir(True) + 'звонки.txt');
end.
Тестировалось на Win7 x86_64 и Linux x86_64.
По хорошему надо еще одну CriticalSection и StringList для держания в нём название файла пока поток работает.
У вас нет необходимых прав для просмотра вложений в этом сообщении.