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

Вниз

Продолжение дискуссии "Как избежать гонок в потоках"   Найти похожие ветки 

 
Игорь Шевченко ©   (2005-06-03 17:55) [80]

Alexander Panov ©   (03.06.05 17:49) [79]

Я несколько к другому. То есть, мне из запущенного примера даже непонятно, корректно ли она работает или некорректно. Уж если делать демку, то так, чтобы было видно, в одном мемо, например, записанные данные, в другом - прочитанные, чтобы можно было проверить, что то, что записано, оно и прочиталось. Чтобы можно было остановить процесс, наконец :)


 
Alexander Panov ©   (2005-06-03 18:01) [81]

Игорь Шевченко ©   (03.06.05 17:55) [80]
-)
Данных-то много, как же их отобразишь?


 
Alexander Panov ©   (2005-06-03 18:01) [82]

Хотя и такой пример можно нарисовать


 
Игорь Шевченко ©   (2005-06-03 18:06) [83]


> Данных-то много, как же их отобразишь?


В двух мемо с возможностью паузы для просмотра.


 
Igorek ©   (2005-06-03 18:16) [84]

Игорь Шевченко ©   (03.06.05 17:48) [78]
И нафига, спрашивается ?

Мда. Устал, ухожу.


 
Игорь Шевченко ©   (2005-06-03 21:44) [85]

Igorek ©   (03.06.05 18:16) [84]

То, что ты процитировал из Рихтера, никоим боком не относится к дискуссии о терминологии, и, более того, никоим боком не опровергает ничьи аргументы. Потому, собственно и вопрос.


 
Igorek ©   (2005-06-04 13:07) [86]

Игорь Шевченко ©   (03.06.05 21:44) [85]
Процитированое в [76] относится практически ко всему в данной ветке и сразу все ставит на свои места.
--
Ладно.
Желающим предлагается самостоятельно доказать почему:
1) схема в [7] есть решением задачи [2] с ограничениями и не требует вообще никаких дополнительных модификаций (разве только уточнения, что писатель освобождает S2, а потом S1)
2) алгоритмы от Verg © не решают задачу [2] ни с ограничениями ни без
--
2panov
Вот вам подробнее.

//Сначала главный поток:
InitializeCriticalSection(S1)
InitializeCriticalSection(S2)
//..
//Читатель:
EnterCriticalSection(S2);
//чтение
LeaveCriticalSection(S2);
//..
//Писатель:
EnterCriticalSection(S1);
EnterCriticalSection(S2);
//запись текущей порции данных
LeaveCriticalSection(S2);
LeaveCriticalSection(S1);
//..
//И в конце главный поток:
DeleteCriticalSection(S1);
DeleteCriticalSection(S2);


 
Alexander Panov ©   (2005-06-04 16:24) [87]

Igorek ©   (04.06.05 13:07) [86]
2) алгоритмы от Verg © не решают задачу [2] ни с ограничениями ни без


Мне сложно сформулировать, что это означает. Есть 3 варианта:

1. Демагогия(так как нет никаких аргуменов).
2. Ламеризм(см. п.1).
3. Тупая упертость(см. пп.1-2).

Ну и п.4 - Нетерпимость к чужому мнению, причем бездоказательно.
--------------------------------
Из. пп.1-3 не следует, что приведенная Verg схема является единственным решением.
--------------------------------

Прошу не обижаться, так как просто такое мнение создается, когда без аргументов пытаются охаять одно и точно так же без аргументов, кинуть свою идею.
--------------------------------

Что касается решения с 2-мя CS.

Решение красивое.
И на 99,9% я уверен, что он рабочее.
Но одно сомнение закрадывается вот в каком плане:

В момент окончания записи текущей порции данных

EnterCriticalSection(S1);
EnterCriticalSection(S2);
//запись текущей порции данных
LeaveCriticalSection(S2);
LeaveCriticalSection(S1);


Читающий поток находится в ожидании S2.
В этот момент писательпокидает секции S2, затем S1. Другой W пытается входит в S1, затем пытается войти в секцию S2.

Может ли другой W войти в секцию S2 раньше, чем R, так как в отношении выделения ресурсов система не поддерживает принцип очереди "Первый вошел, первый вышел"?

Если такой вариант возможен, то схема неработоспособна.
Это единственное сомнение.


 
Alexander Panov ©   (2005-06-04 16:26) [88]

Igorek ©   (04.06.05 13:07) [86]

И, кстати, сапсибо за решение. Весьма простая схема.


 
Verg ©   (2005-06-04 17:41) [89]


> Мне сложно сформулировать, что это означает.


Мне тоже. Кроме того, что я и не пытался опровергнуть очевидности решения с двумя КС, я просто предложил другой вариант (альтарнатива, если помнит кое-кто такое слово). Кому не нравится, тому не нравится.
Про аргументацию здесь, видимо, неприлично спрашивать вообще.

"не кажется ли вам. уважаемые судари, что сабж перешел в статус "мерянье концами" ?)"

(С) Digitman
http://delphimaster.net/view/1-1117521494/


 
Igorek ©   (2005-06-04 17:54) [90]

Alexander Panov ©   (04.06.05 16:24) [87]
Есть 3 варианта:
Ну и п.4

Могу посоветовать расширять кругозор.
Alexander Panov ©   (04.06.05 16:24) [87]
охаять

Понимайте как хотите. Если человек неправ, я говорю об этом прямо "вы неправы". Я же не говорю "вы или демагог или ламер или упертый тупица или нетерпимы к чужому мнению, причем бездоказательно". Аргументирую по мере сил и времени. Ключевым аргументом является пост [76] (уж не знаю как выделить), после которого все ясно. Я сам сомневался в некоторых вещах, пока не глянул Рихтера.

Alexander Panov ©   (04.06.05 16:24) [87]
Читающий поток находится в ожидании S2.
В этот момент писательпокидает секции S2, затем S1. Другой W пытается входит в S1, затем пытается войти в секцию S2.
Может ли другой W войти в секцию S2 раньше, чем R, так как в отношении выделения ресурсов система не поддерживает принцип очереди "Первый вошел, первый вышел"?
Если такой вариант возможен, то схема неработоспособна.
Это единственное сомнение.

Сомнение совершенно беспочвенное. Во-первых потоки, которые ждут. крит секцию не жрут кванты процессора, и потому не учавствуют в дипетчеризации (это к тому, что квант времени попадет другому писателю, ну и перехват крит. секции - неверно мягко говоря). Во-вторых как только писатель освобождает S2, эту секцию сразу же захватывает читатель, что очевидно из второго абзаца цитаты. Читатель сразу включается в диспетчеризацию. Хотя вопрос "получит ли он сразу квант времени?" для меня лично остается открытым. Ну и принцип fifo тут не в тему, согласитесь (ожидает то только один поток).
--
Все, бегу на день рождения.. :)


 
Verg ©   (2005-06-04 18:12) [91]


> Igorek ©   (04.06.05 17:54) [90]


> Понимайте как хотите. Если человек неправ, я говорю об этом
> прямо "вы неправы". Я же не говорю "вы или демагог или ламер
> или упертый тупица или нетерпимы к чужому мнению, причем
> бездоказательно".


Нет уж, дорогой, вы не говорите "вы не правы", вы высокомерно предлагаете другим это сказать ("Желающим предлагается самостоятельно доказать почему").

Так что, "ля-ля" это все. Пустой звук.


 
Alexander Panov ©   (2005-06-04 18:16) [92]

Igorek ©   (04.06.05 17:54) [90]
Хотя вопрос "получит ли он сразу квант времени?" для меня лично остается открытым.


Вопрос не в том, получит ли читающий поток квант времени сразу, а в том, не успеет ли до этого другой поток войти в критическую секцию.

В варианте от Verg такой вариант исключен.


 
Igorek ©   (2005-06-05 12:13) [93]

Verg ©   (04.06.05 17:41) [89]
"мерянье концами" ?)"

Бабы мерялись на даче,
у кого звезда лохмаче.
Оказалось, что лохмаче,
у самой хозяйки дачи!

Ладно, не будем сорится. :)
Если уж бабы любят мерятся, то мужики и подавно. :))

--
Теперь по сути, по [30].
Возьмем пример:
Есть 100 потоков (99 W, и 1 R).
Все ломанулись к буферу. Читатель ломанулся последним. Возникла ситуация - один писатель захватил крит. секцию, но не успел проверить флажок. Остальные 98 и читатель зависли в захвате. Писатель проверяет флажок, освобождает крит. секцию. Я сомневаюсь, что крит. секцию сразу получит читатель. Если действует fifo, то еще 98 писателей войдут и выйдут из крит. секции. Где я неправ?


 
Alexander Panov ©   (2005-06-05 14:05) [94]

Igorek ©   (05.06.05 12:13) [93]
Где я неправ?


вот здесь:
Если действует fifo, то еще 98 писателей войдут и выйдут из крит. секции.

Не действует fifo.


 
Alexander Panov ©   (2005-06-05 14:06) [95]

А пример оказалось весьма сложно сделать для проверки схемы с 2-мя критическими секциями.
МНе пока не удалось оттестироват момент, приведенный в [87] и [92].


 
Игорь Шевченко ©   (2005-06-06 11:11) [96]

Да сделайте вы обычную очередь и не мучайтесь


 
GrayFace ©   (2005-06-06 11:19) [97]

Игорь Шевченко ©   (03.06.05 15:08) [65]
Матчасть ?

Отчасти согласен. Передать квант проц. времени конкретному потоку нельзя - спутал. Но к какой части поста замечание?

Alexander Panov ©   (04.06.05 18:16) [92]
Вопрос не в том, получит ли читающий поток квант времени сразу, а в том, не успеет ли до этого другой поток войти в критическую секцию.

Если верить Рихтеру, распределение CS происходит при вызое LeaveCS, а не при раздаче кванта проц. времени. Крит. секция тут же отдается другому потоку и никто не может успеть ее захватить, т.к. все W ждут другой CS.


 
evvcom ©   (2005-06-06 14:06) [98]


> Если есть хотя бы один такой поток, функция настраивает
> значения элементов структуры, что бы они сигнализировали
> о занятости ресурса, и отдает его одному из ждущих потоков

Здесь нет слова "немедленно", по сему всё же только тестирование может доказать или опровергнуть достаточности только крит.секций для решения поставленной задачи. Хотя может кто-нибудь точно знает, что делает ntdll.RtlpUnWaitCriticalSection?


 
evvcom ©   (2005-06-06 21:58) [99]

Написал тест:

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
   Button1: TButton;
   Memo1: TMemo;
   procedure Button1Click(Sender: TObject);
 private
   procedure WMPrintMessage(var Message: TMessage); message WM_USER;
 public
   { Public declarations }
 end;

 TMyThread = class(TThread)
 private
   FName: string;
   FWriter: Boolean;
 protected
   procedure Execute; override;
 public
   constructor Create(AName: string; AWriter: Boolean);
 end;

var
 Form1: TForm1;
 List1: TStringList;
 CSR: TRTLCriticalSection;
 CSW: TRTLCriticalSection;
 CSL: TRTLCriticalSection;

implementation

{$R *.dfm}

procedure PrintMessage(AThread: TMyThread; AMessage: string);
var
 l_iIndex: Integer;
begin
 EnterCriticalSection(CSL);
 l_iIndex := List1.Add(Format("Поток %s: %s", [AThread.FName, AMessage]));
 PostMessage(Form1.Handle, WM_USER, l_iIndex, 0);
 LeaveCriticalSection(CSL);
end;

{ TMyThread }

constructor TMyThread.Create(AName: string; AWriter: Boolean);
begin
 FName := AName;
 FWriter := AWriter;
 FreeOnTerminate := True;
 inherited Create(False);
 Sleep(500);
end;

procedure TMyThread.Execute;
begin
 if FWriter then begin
   PrintMessage(Self, "Вход в крит. секцию CSW");
   EnterCriticalSection(CSW);
   PrintMessage(Self, "В крит. секцию CSW вошел");
 end;

 PrintMessage(Self, "Вход в крит. секцию CSR");
 EnterCriticalSection(CSR);
 PrintMessage(Self, "В крит. секцию CSR вошел. Вычисление");
 Sleep(5000);
 PrintMessage(Self, "Выход из крит. секции CSR"#13#10);
 LeaveCriticalSection(CSR);
 PrintMessage(Self, "Из крит. секции CSR вышел");

 if FWriter then begin
   PrintMessage(Self, "Выход из крит. секции CSW"#13#10);
   LeaveCriticalSection(CSW);
   PrintMessage(Self, "Из крит. секции CSW вышел");
 end;
end;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
 Memo1.Clear;
 TMyThread.Create("W1", True);
 TMyThread.Create("W2", True);
 TMyThread.Create("R", False);
end;

procedure TForm1.WMPrintMessage(var Message: TMessage);
begin
 EnterCriticalSection(CSL);
 Memo1.Lines.Add(List1.Strings[Message.WParam]);
 LeaveCriticalSection(CSL);
end;

initialization
 InitializeCriticalSection(CSR);
 InitializeCriticalSection(CSW);
 InitializeCriticalSection(CSL);
 List1 := TStringList.Create;

finalization
 DeleteCriticalSection(CSR);
 DeleteCriticalSection(CSW);
 DeleteCriticalSection(CSL);
 List1.Free;

end.

Результаты теста:

Поток W1: Вход в крит. секцию CSW
Поток W1: В крит. секцию CSW вошел
Поток W1: Вход в крит. секцию CSR
Поток W1: В крит. секцию CSR вошел. Вычисление
Поток W2: Вход в крит. секцию CSW
Поток R: Вход в крит. секцию CSR
Поток W1: Выход из крит. секции CSR

Поток R: В крит. секцию CSR вошел. Вычисление
Поток W1: Из крит. секции CSR вышел
Поток W1: Выход из крит. секции CSW

Поток W2: В крит. секцию CSW вошел
Поток W2: Вход в крит. секцию CSR
Поток W1: Из крит. секции CSW вышел
Поток R: Выход из крит. секции CSR

Поток W2: В крит. секцию CSR вошел. Вычисление
Поток R: Из крит. секции CSR вышел
Поток W2: Выход из крит. секции CSR

Поток W2: Из крит. секции CSR вышел
Поток W2: Выход из крит. секции CSW

Поток W2: Из крит. секции CSW вышел

Тест провел несколько раз, результат один. Очень похоже, что ОС действительно ведет себя, как пишет Igorek. Но тем не менее в первоисточниках вроде как нигде незадокументировано подобное поведение системы, что не позволяет нам быть уверенными в том, что и будушие версии винды будут вести себя так же.


 
Verg ©   (2005-06-07 06:03) [100]


> Igorek ©   (05.06.05 12:13) [93]


> Если действует fifo, то еще
> 98 писателей войдут и выйдут из крит. секции. Где я неправ?


Ну и ...? Так они и выйдут, они выполнят пункт 3 задания - "При этом все остальные потоки W должны немедленно прекратить свою работу по записи буфера, кроме потока, который в данный момент заполняет буфер."
Другими словами читатель потратит времени на чтение из буфера не более того, что тратит один писатель на запись плюс время собственно чтения, пусть их хоть тыща желающих записать.

program OneReader;

{$APPTYPE CONSOLE}

uses
 Windows,
 SysUtils,
 Classes,
 SyncObjs;

type
 TWriteThread = class( TThread )
 public
   constructor Create();
   procedure Execute; override;
 end;

var
S : TCriticalSection;
ReaderInQue : integer;

 FCount  : integer;
 FAvgTime : int64;
 FMaxTime : cardinal;

procedure InternalWriteBuffer( const Data; Size : cardinal );
begin
 Sleep( 500 );
end;

function InternalReadBuffer( var Data; BufferSize : cardinal ) : cardinal;
begin
 Result := 0;
end;

procedure WriteBuffer( const Data; Size : cardinal );
label l1;
begin
l1:
  S.Enter;

  if ReaderInQue <> 0 then
  begin
    S.Leave;
    Goto l1;
  end;

  InternalWriteBuffer( Data, Size );

  S.Leave;
end;

function ReadBuffer( var Data; BufferSize : cardinal ) : cardinal;
begin
InterLockedIncrement( ReaderInQue );
S.Enter;

Result := InternalReadBuffer( Data, BufferSize );

InterLockedDecrement( ReaderInQue );
S.Leave;
end;

constructor TWriteThread.Create;
begin
 FreeOnTerminate := true;
 inherited Create( false );
end;

procedure   TWriteThread.Execute;
var D : integer;
begin
 while not Terminated do
 begin
   Sleep( Random(5) );
   WriteBuffer( D, sizeof(D));
 end;
end;

var i : integer;
   T : cardinal;
   D : integer;
begin
 Randomize;

 ReaderInQue :=0;
 FCount      :=0;
 FAvgTime    :=0;
 FMaxTime    :=0;

 S        := TCriticalSection.Create;

 for i:=1 to 300 do
 begin
   TWriteThread.Create;
 end;

 while true do
 begin
   Sleep(Random( 30 ) );
   T := GetTickCount;
   ReadBuffer( D, sizeof(D));
   T := GetTickCount - T;
   if( T > FMaxTime ) then FMaxTime := T;
   inc( FAvgTime, T );
   inc( Fcount) ;
   WriteLn( T, #9, FAvgTime / FCount : 3:2, #9, FMaxTime);
 end;

end.


 
evvcom ©   (2005-06-07 09:02) [101]

В дополнение к evvcom ©   (06.06.05 21:58) [99]:
Попытался потом попозже еще отладчиком прошагать по LeaveCriticalSection, RtlpUnWaitCriticalSection и др., чтобы хоть примерно увидеть, где происходит смена контекста потока. Результат - смены контекста не произошло, результаты изменились, и я увидел

Поток W1: Выход из крит. секции CSR
Поток W1: Из крит. секции CSR вышел
Поток W1: Выход из крит. секции CSW

и только потом где-то

Поток R: В крит. секцию CSR вошел. Вычисление

Т.е. вышло, что присутствие отладчика изменило логику работы программы, что свидетельствует о том, что все же алгоритм не надежен. Собственно, что я изначально и предполагал.


 
Alexander Panov ©   (2005-06-07 10:05) [102]

evvcom ©   (06.06.05 21:58) [99]
evvcom ©   (07.06.05 9:02) [101]

К сожалению, не только присутствие отладчика изменит порядок работы потоков, но и вывод отладочной информации.
В этом и трудность - написать тест, который не исказит результаты.


 
Igorek ©   (2005-06-07 10:22) [103]

evvcom ©   (07.06.05 9:02) [101]
где происходит смена контекста потока. Результат - смены контекста не произошло

Что такое "контекст потока"? Как его можно увидеть в отладчике?

evvcom ©   (07.06.05 9:02) [101]
что свидетельствует о том, что все же алгоритм не надежен

Неа. Это свидетельствует только о том, что читатель не получил квант времени сразу после захвата CSR и не успел послать сообщение. О чем я и писал:
Igorek ©   (04.06.05 17:54) [90]
Читатель сразу включается в диспетчеризацию. Хотя вопрос "получит ли он сразу квант времени?" для меня лично остается открытым.

Если ты правильно протестировал, то ответ - "не обязательно".

Verg ©   (07.06.05 6:03) [100]
Так они и выйдут, они выполнят пункт 3 задания - "При этом все остальные потоки W должны немедленно прекратить свою работу по записи буфера, кроме потока, который в данный момент заполняет буфер."

Вы слишко вольно трактуете термин "Немедленно". А я наверно слишком свободно термин "холостой" цикл. Собственно эти входы и выходы мне кажутся именно холостыми.
Verg ©   (07.06.05 6:03) [100]
Другими словами читатель потратит времени на чтение из буфера не более того, что тратит один писатель на запись плюс время собственно чтения, пусть их хоть тыща желающих записать.

А мильен? А мильярд? Время, которое читатель потратит времени на чтение из буфера вообще зависит от колл. писателей в очереди?

Кроме того в свете поста [101] возникает еще одно сомнение. Если писатель покидает крит. секцию, это еще не значит, что он потеряет контекст процессора. Значит он снова может успеть встать в очередь на крит. секцию. А учитывая, что fifo не гарантировано, даже еще раз ее захватить. Как-то это все меньше похоже на "немедленно".


 
Игорь Шевченко ©   (2005-06-07 10:25) [104]


> Что такое "контекст потока"? Как его можно увидеть в отладчике?


С правой стороны :)


 
evvcom ©   (2005-06-07 11:10) [105]


> Как его можно увидеть в отладчике?

Ctrl+Alt+T


 
Igorek ©   (2005-06-07 11:54) [106]

Игорь Шевченко ©   (07.06.05 10:25) [104]
С правой стороны :)

Не умничай. У меня там системный блок. А дальше мебель.. Что я делаю неправильно?!! :(


 
Игорь Шевченко ©   (2005-06-07 12:01) [107]

Igorek ©   (07.06.05 11:54) [106]


> У меня там системный блок. А дальше мебель


Переставь на другую сторону и увидишь контекст потока


 
evvcom ©   (2005-06-07 13:06) [108]

Еще идея. Каждый W, заметив запрос R, выполняет Suspend. R отработав, будит все W. Это предотвратит замечания [103].
Только мне интересен такой вариант, а если R, выставляя свой флаг, вызовет для всех W Suspend (ну кроме того, который уже возможно занял секцию CSR), не давая шансов им войти в секцию, не приведет ли это к глюкам?


 
GrayFace ©   (2005-06-09 10:16) [109]

Igorek ©   (07.06.05 11:54) [106]
Не умничай. У меня там системный блок. А дальше мебель.. Что я делаю неправильно?!! :(

:)))

Когда поток исчерпывает квант проц. времени регистры процессора и т.п. сохраняются в его контекст и загружаются из контекста потока, получившего квант.

evvcom ©   (07.06.05 13:06) [108]
Только мне интересен такой вариант, а если R, выставляя свой флаг, вызовет для всех W Suspend (ну кроме того, который уже возможно занял секцию CSR), не давая шансов им войти в секцию, не приведет ли это к глюкам?

Приведет к пустой трате времени, ведь основная часть W занята своей работой и на CS не претендуют.

PS Но лучший вариант - посылка сообщения со строкой.



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

Форум: "Потрепаться";
Текущий архив: 2005.07.11;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.69 MB
Время: 0.045 c
9-1112329942
Strech
2005-04-01 08:32
2005.07.11
Физика твердого тела и борьба с дискретностью


5-1089664919
boband
2004-07-13 00:41
2005.07.11
Как управлять прорисовкой кнопки?


3-1117477869
alex-drob
2005-05-30 22:31
2005.07.11
Всегда ли нужно BDE


1-1118643932
Руслана
2005-06-13 10:25
2005.07.11
Два вопроса по массивам


8-1109878979
capkoh
2005-03-03 22:42
2005.07.11
PNG на форме...





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