Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как избежать гонок в потоках [D6, WinXP]


Страницы:   1 2 3 4 5

leonidus ©   (2005-05-31 10:38:00) 

Мастера подскажите пожалуйста. Я написал небольшую программу, она скачивает новости с разных сайтов, и затем парсит каждую скачанную страницу на предмет нужной информации. Т.е. программа состоит из бвух блоков - блок закачки (качается сразу в несколько потоков, для каждой страницы с новостями свой поток) и блок парсинга (в нем также предусмотрена многопоточность, при этом для каждой скачанной страницы должен запускаться свой экземпляр одного и тогоже потока). Результаты парсинга (заголовки новостей) помещаются в массив. И вот в чем проблема. Если одновременно скачаются две страницы и одновременно начнут работать два парсера, то может так получиться, что они будут обращаться к одному элементу массив, что бы записать в него полученный заголовок новости. Т.е. я тап понимаю это ситуация гонок. Подскажите как этого избежать. Может есть какие-то статьи по этому поводу, я что-то ничего толком не нашел. Заранее спасибо.


leonidus   (2005-06-01 10:55:00) [61]

Ок, тобишь процедура работы с массивом должна выглядеть так? :

procedure TThread_work.Execute;
begin
FCS.Enter;
try
 inc(nom);
 a[nom]:=st1;
 inc(nom);
 a[nom]:=st2;
 inc(nom);
 a[nom]:=st3;
 synchronize(showresult);
finally
 FCS.Leave;
end;
end;

т.е. synchronizeиспользую до FCS.Leave так?

[13] "Нифига подобного. Никто не мешает другому потоку менять содержимое массива во время исполнения метода Syncronize в данном коде."

но к моменту вызова synchronize поток уже свое дело с массивом сделал, т.е. в принципе уже мождо давать доступ к массиву и другому потоку... но с другой стороны критическая секйия еще не закрылась, почему это другой поток должен в нее войти?


КаПиБаРа   (2005-06-01 10:48:00) [62]

Рекомендую почитать
http://mbo88.narod.ru/ToC.html


GrayFace   (2005-06-01 10:48:00) [63]

evvcom ©   (01.06.05 8:30) [22]</>
См. [13].

Defunct ©   (01.06.05 0:24) [19]
Ненадежно, может подвиснуть всё, из-за любого случайного исключения.

Да, че-то я совсем про try забыл.
FCS.Enter;
try
 inc(nom);
 a[nom]:=t.st;

 synchronize(showresult);
finally
 FCS.Leave;
end;


Еще вариант: всю работу с массивом и Memo поместить в одну процедуру и делать ее Synchronize.


Игорь Шевченко   (2005-06-01 10:43:00) [64]

leonidus ©   (01.06.05 10:42) [23]

Чукча не читатель ? Чукча write-only ?


> procedure TThread_work.Execute;
> begin
> FCS.Enter;
> inc(nom);
> a[nom]:=t.st1;
> inc(nom);
> a[nom]:=t.st2;
> inc(nom);
> a[nom]:=t.st3;


Убрать нахрен t.


leonidus   (2005-06-01 10:42:00) [65]

Да защищать нужно будет только запись в массив, правда операция может быть продолжительной т.к. массив 1.000.000 элементов, а что продолжительность работы критической секции столь важно? На другой поток конечно переключаться не буду, пока данный полностью не отработает.
А почему поменять местами? Я сейчас сделал так, и прекрасно работает:

  TThread_work = class(TThread)
  private
    { Private declarations }
    st1:string;
    st2:string;
    st3:string;
  protected
    procedure Execute; override;
    procedure showresult;
  public
  end;

var
 Form1: TForm1;
 FCS:TCriticalSection;
 t:TThread_work;
 a:array[1..100] of string;
 nom,n:integer;

implementation

{$R *.dfm}

procedure TThread_work.showresult;
var
i:integer;
begin
inc(n);

if n=2 then
 begin
  for i:=1 to nom do
   begin
    form1.memo1.Lines.Add(a[i]);
   end;
  form1.memo1.Lines.Add('---');
 end
end;

procedure TThread_work.Execute;
begin
FCS.Enter;
inc(nom);
a[nom]:=t.st1;
inc(nom);
a[nom]:=t.st2;
inc(nom);
a[nom]:=t.st3;

synchronize(showresult);
FCS.Leave;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
FCS:=TCriticalSection.Create;

n:=0;
nom:=0;

t:=TThread_work.Create(true);
t.FreeOnTerminate:=true;
t.st1:='поток1: message1';
t.st2:='поток1: message2';
t.st3:='поток1: message3';
t.Resume;

t:=TThread_work.Create(true);
t.FreeOnTerminate:=true;
t.st1:='поток2: message1';
t.st2:='поток2: message2';
t.st3:='поток2: message3';
t.Resume;
end;


evvcom   (2005-06-01 08:30:00) [66]


> leonidus ©   (01.06.05 07:57) [21]

Что у тебя FCS защищает? Массив? Вот и защищай только массив. Используй блокировки как можно на меньшее время. И тем более не переключайся на другой поток, оставив заблокированной критическую секцию. В концовке надо поменять местами строки:

FCS.Leave; // Сначала разблокируй
synchronize(showresult); // а потом в другой поток


leonidus   (2005-06-01 07:57:00) [67]

>Defunct что значит "может подвиснуть всё, из-за любого случайного исключения" поясните плиз мысль?


Marser   (2005-06-01 00:37:00) [68]


> Вообще, CriticalSection работает гораздо быстрее, чем
> Synchronize. Но для общения с контролами от
> Synchroniz'а, обычно, никуда не убежать.

Вот это оно. TCriticalSection - инкапсуляция очень полезного объекта API. потому и быстрая. И для невизуальных данным прекрасно подходит.
Synchronize реализует тот же принцип исключения многопоточного доступа к данным, но эти данные - объекты VCL, а основная цель - исключение одновременного доступа к DC.

P.S. А ещё есть
InterlockedCompareExchange
InterlockedDecrement
InterlockedExchange
InterlockedExchangeAdd
InterlockedIncrement


Defunct   (2005-06-01 00:24:00) [69]

FCS.Enter;
inc(nom);
a[nom]:=t.st;

synchronize(showresult);
FCS.Leave;
end;

Ненадежно, может подвиснуть всё, из-за любого случайного исключения.


GrayFace   (2005-05-31 23:41:00) [70]

leonidus ©   (31.05.05 21:29) [17]
ок, значит мой пример никик к нормальному виду переделать не удасться?

Да он почти правильный. Ну вот так:
FCS.Enter;
inc(nom);
a[nom]:=t.st;

synchronize(showresult);
FCS.Leave;
end;


Только не вздумай в осн.потоке вызвать WaitForMultipleObjects и т.п. для потоков-обработчиков!

Вообще, CriticalSection работает гораздо быстрее, чем Synchronize. Но для общения с контролами от Synchroniz'а, обычно, никуда не убежать.

PS: Все это ИМХО.


leonidus   (2005-05-31 21:29:00) [71]

ок, значит мой пример никик к нормальному виду переделать не удасться?


Erik1   (2005-05-31 17:17:00) [72]

Пример тебе хороший нужен. У меня есть неплохой с использованием TMultiReadExclusiveWriteSynchronizer. Там два списка в потоках обрабатываются, но 11кб фаил занимает, там разумеется дополнительная логика присудствует.


Игорь Шевченко   (2005-05-31 16:39:00) [73]

Alexander Panov ©   (31.05.05 16:23) [14]

В примере два потока, кроме основного.


Alexander Panov   (2005-05-31 16:23:00) [74]

Игорь Шевченко ©   (31.05.05 16:04) [13]
Никто не мешает другому потоку менять содержимое массива


Так в примере подразумевается, что доугих потоков нет(кроме основного, конечно).


Игорь Шевченко   (2005-05-31 16:04:00) [75]

Alexander Panov ©   (31.05.05 15:41) [11]


> Для того и Synchronize


Нифига подобного. Никто не мешает другому потоку менять содержимое массива во время исполнения метода Syncronize в данном коде.

RTFM.


Семен Сорокин   (2005-05-31 15:45:00) [76]


> Alexander Panov ©   (31.05.05 15:41) [11]
> Семен Сорокин ©   (31.05.05 15:37) [10]
> а то что мы в мемо одновременно двумя потоками пишем?
>
> Для того и Synchronize;)

все понял :)

>leonidus ©   (31.05.05 15:31) [8]

Признаю, не прав, см.[9].


Alexander Panov   (2005-05-31 15:41:00) [77]

Семен Сорокин ©   (31.05.05 15:37) [10]
а то что мы в мемо одновременно двумя потоками пишем?


Для того и Synchronize;)


Семен Сорокин   (2005-05-31 15:37:00) [78]


> а при чем тут synchronize(showresult)?
> как будет привильно?

то что глобальные переменные меняются через КС - это нормально, а то что мы в мемо одновременно двумя потоками пишем?


Игорь Шевченко   (2005-05-31 15:37:00) [79]


> a[nom]:=t.st;


a[nom] := st;


leonidus   (2005-05-31 15:31:00) [80]

а при чем тут synchronize(showresult)?
как будет привильно?


Страницы:   1 2 3 4 5

Наверх

Титульная страница Поиск, карта сайта Написать письмо