Главная страница
    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
Время: 1.512 c
4-1147163914
angelsaint
2006-05-09 12:38
2006.09.03
создание и обработка своих сообщений


3-1151048150
zdm
2006-06-23 11:35
2006.09.03
FASTReport нумерация полей


2-1155750524
pvi
2006-08-16 21:48
2006.09.03
CreateRemoteComObject


15-1155060007
зеркальщик
2006-08-08 22:00
2006.09.03
The command you selected is not available


2-1155141635
Johnny_Row
2006-08-09 20:40
2006.09.03
процедура в отдельном потоке выполняется медленнее в 2 раза





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский