Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.09.03;
Скачать: CL | DM;

Вниз

Потокозащищенный список строк   Найти похожие ветки 

 
Лапыч ©   (2006-07-20 11:15) [0]

Покопавшись в VCL и посмотрев класс TStringList, я заметил, что практически перед каждым изменением списка вызывается метод Changing, а после изменения - метод Changed. Решил сделать так:

interface

type
 TThreadSafeStringList=class(TStringList)
 private
   fLocker: TCriticalSection;
 protected
   procedure Lock;
   procedure Unlock;
   procedure Changed; override;
   procedure Changing; override;
   function Get(Index: Integer): string; override;
   function GetObject(Index: Integer): TObject; override;
   function GetCount: Integer; override;
   function GetCapacity: Integer; override;
   procedure SetCapacity(NewCapacity: Integer); override;
 public
   constructor Create;
   destructor Destroy; override;
 end;

implementation

constructor TThreadSafeStringList.Create;
begin
 fLocker:=TCriticalSection.Create;
end;

destructor TThreadSafeStringList.Destroy;
begin
 inherited;
 fLocker.Free;
end;

procedure TThreadSafeStringList.Lock;
begin
 fLocker.Enter;
end;

procedure TThreadSafeStringList.Unlock;
begin
 fLocker.Leave;
end;

procedure TThreadSafeStringList.Changing;
begin
 Lock;
 inherited;
end;

procedure TThreadSafeStringList.Changed;
begin
 inherited;
 Unlock;
end;

function TThreadSafeStringList.Get(Index: Integer): string;
begin
 Lock;
 try
   Result:=inherited Get(Index);
 finally
   Unlock;
 end;
end;

function TThreadSafeStringList.GetObject(Index: Integer): TObject;
begin
 Lock;
 try
   Result:=inherited GetObject(Index);
 finally
   Unlock;
 end;
end;

function TThreadSafeStringList.GetCount: Integer;
begin
 Lock;
 try
   Result:=inherited GetCount;
 finally
   Unlock;
 end;
end;

function TThreadSafeStringList.GetCapacity: Integer;
begin
 Lock;
 try
   Result:=inherited GetCapacity;
 finally
   Unlock;
 end;
end;

procedure TThreadSafeStringList.SetCapacity(NewCapacity: Integer);
begin
 Lock;
 try
   inherited;
 finally
   Unlock;
 end;
end;


Один поток постоянно добавляет строки в список, другой их удаляет в цикле:

var
 S: string;
begin
 while ThreadSafeStringList.Count>0 do
 begin
   S:=ThreadSafeStringList[0];
   DoSomething(S);
   ThreadSafeStringList.Delete(0);
 end;
end;


При выполнении
S:=ThreadSafeStringList[0];
очень редко, но все же происходит Access Violation.


 
umbra ©   (2006-07-20 11:40) [1]

может быть, стоит перекрыть и метод Delete?

procedure TStringList.Delete(Index: Integer);
begin
 if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index);
 Changing;
 Finalize(FList^[Index]);
 Dec(FCount); // мне кажется, что дело в этой строке
 if Index < FCount then
   System.Move(FList^[Index + 1], FList^[Index],
     (FCount - Index) * SizeOf(TStringItem));
 Changed;
end;


 
Лапыч ©   (2006-07-20 11:47) [2]

2umbra:
Обоснуйте, пожалуйста, своё предположение.
Спасибо.


 
umbra ©   (2006-07-20 11:59) [3]

да, похоже я вспылил :)
надо подумать. Присвоение и удаление строк происходят только в одном месте, показанном Вами? А исключение - именно EAccessViolation?


 
Slym ©   (2006-07-20 13:31) [4]

TThreadSafeStringList=class
private
  fLocker: TCriticalSection;
  FStringList:TStringList;
public
  constructor Create;
  destructor Destroy; override;
  function Lock:TStringList;
  procedure Unlock;
end;

implementation

constructor TThreadSafeStringList.Create;
begin
fLocker:=TCriticalSection.Create;
 FStringList:=TStringList.Create;
end;

destructor TThreadSafeStringList.Destroy;
begin
 FStringList.Free;
fLocker.Free;
inherited;
end;

function TThreadSafeStringList.Lock:TStringList;
begin
fLocker.Enter;
 result:=FStringList;
end;

procedure TThreadSafeStringList.Unlock;
begin
fLocker.Leave;
end;


 
Slym ©   (2006-07-20 13:32) [5]

var
S: string;
StringList:TStringList;

begin
StringList:=ThreadSafeStringList.Lock;
try
  while ThreadSafeStringList.Count>0 do
  begin
    S:=ThreadSafeStringList[0];
    DoSomething(S);
    ThreadSafeStringList.Delete(0);
  end;
finally
 ThreadSafeStringList.UnLock;
end;
end;


 
Slym ©   (2006-07-20 13:33) [6]

сори...
var
S: string;
StringList:TStringList;
begin
StringList:=ThreadSafeStringList.Lock;
try
 while StringList.Count>0 do
 begin
   S:=StringList[0];
   DoSomething(S);
   StringList.Delete(0);
 end;
finally
ThreadSafeStringList.UnLock;
end;
end;


 
umbra ©   (2006-07-20 13:43) [7]

2 Slym ©

IdThreadSafe? :)


 
Лапыч ©   (2006-07-20 15:32) [8]

2Slym:
Потокозащищенный класс TThreadSafeStringList (впрочем, как и все полностью потокозащищенные классы) скрывают (инкапсулируют, если хотите) реализацию механизма доступа к данным. Вызов методов Lock и Unlock должен происходить автоматически при вызове других методов, грозящих ошибкой совместного и одновременного (в терминах вытесняющей многозадачности) доступа к данным.


 
Slym ©   (2006-07-21 05:03) [9]

И что ты меня учишь? TThreadList посмотри.
Где у тебя здесь защита?
var
S: string;
begin
while ThreadSafeStringList.Count>0 do
begin
  S:=ThreadSafeStringList[0];
  DoSomething(S);
  ThreadSafeStringList.Delete(0);
end;
end;

пример:
Поток 1 зашел в
while ThreadSafeStringList.Count>0 do
begin
и был остановлен до
S:=ThreadSafeStringList[0];
поток 2 получил управление и сделал
ThreadSafeStringList.Clear;
поток 1 продолжил выполнение
S:=ThreadSafeStringList[0];
но ожидаемого нулевого элемента уже нету :) вот тебе и Лапыч ©   (20.07.06 11:15)происходит Access Violation.


 
Slym ©   (2006-07-21 05:05) [10]

Твой класс защищает вызовы внутри методов класса, но не защищает между ними :(


 
Лапыч ©   (2006-07-24 09:30) [11]

Всё уже - разобрался с этим. Всем спасибо за внимание и понимание:)



Страницы: 1 вся ветка

Текущий архив: 2006.09.03;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.056 c
1-1152376503
Baitur
2006-07-08 20:35
2006.09.03
Unicode


2-1155152996
ArtemESC
2006-08-09 23:49
2006.09.03
Canvas


9-1133771636
@!!ex
2005-12-05 11:33
2006.09.03
OpenGL на ATI и Intel


2-1155386675
SamProf
2006-08-12 16:44
2006.09.03
Как получить handle фокусного объекта


9-1134035185
kblc
2005-12-08 12:46
2006.09.03
BlackJack