Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2006.09.03;
Скачать: [xml.tar.bz2];

Вниз

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

 
Лапыч ©   (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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.48 MB
Время: 0.035 c
15-1155239556
TGX
2006-08-10 23:52
2006.09.03
Проблемы с монитором!


2-1155346950
Gamer
2006-08-12 05:42
2006.09.03
ShareWare в xUSSR


15-1154692981
QuickFinder
2006-08-04 16:03
2006.09.03
метод POST


15-1155200636
parovoZZ
2006-08-10 13:03
2006.09.03
BDE Administrator


2-1155477729
AlexanderMS
2006-08-13 18:02
2006.09.03
Изменение стандартных диалогов.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский