{{notification.text}}

MirGames

07.05.08 15:47
0
Задумался тут о потоках я, и вот значит сижу и не могу понять их суть, прошу объсните, есть смысл их использования? Можно ли таким образом ускорить скорость выполнения программы?)))
Короче, прошу расскажите кто что знает...

P.S. В интернете ничего дельного не нашёл
P.P.S. На MSDN, Google и т.п. не посылать (прим. пер. а куда тебя послать?)

Перевод на русский выполнил XProger
Отредактировано: 07.05.08 19:54
#1
07.05.08 16:06
0
С таким вопросом, повысят они в первую очередь забагованность программы :) А вообще, потоки позволяют
1) Делать одновременно нескольк задач (условно одновременно)
2) Заюзать на мультипроцессорной/многоядерной системе более чем один проц.
Почитать о них можно для начала в хороших книжках по дельфи. Подозреваю, Тейксейра и Пачеко или Марко Кэнту такую тему осветили (точно не знаю, не читал к сожалению).
#2
Почётный лектор
07.05.08 16:14
0
Цитата(Vga @ Сегодня, 12:06)
[snapback]79842[/snapback]
они в первую очередь забагованность программы

К сожалению, чистая правда :(
#3
07.05.08 16:35
0
а поток по окончанию будет второй раз вызыватсья?
Цитата(Vga @ Сегодня, 12:06)
[snapback]79842[/snapback]
забагованность программы

в чём это выражается?
#4
Mirage
07.05.08 16:58
0
Нет, не будет. В потоке цикл делают.
Вообще потоки нужны когда нужны, а не просто так. Писать с их использованием надо уметь, чтобы не было одновременных обращений к одим и тем же данным и т.п. Иначе будут трудноуловимые глюки, выражающиеся в чем угодно.
#5
Почётный лектор
07.05.08 18:02
0
О проблемах. Важно понимать, что потоки взаимодействуют. Используют общие данные, к примеру, вызывают общие функции. Иначе никакого смысла в потоках не будет - они будут полностью неуправляемы. Тут и начинаются проблемы - чтобы два потока одновременно не начали менять один и тот же объект или не вызвали функцию, которая предполагает неделимое исполнение. Приходится использовать критические секции, события и прочую лабуду.

Вот пример из жизни (на данный момент окончательно не разрешен) - ГеймСпай расчитан на последовательное выполнение своих функций, иначе ай-ай. Этого можно достичь только если весь код, связанный с GameSpy'ем работает в единственном потоке. В основном потоке этого делать нельзя - иначе оно временами будет блокировать работу основной программы, к примеру рендер. Значит выносим в отдельных поток. Всё нормально, пока управлять этим потоком мы не начинаем из внешнего потока. По хорошему - вызов всех функций геймспая надо оборачивать в свои потокобезопасные функции, которые вызываются тогда, когда им следует - из потока для геймспая. Тогда, чтобы вызвать такую операцию из основного потока надо попросить систему, разруливающую это всё вызвать такую-то вещь когда придет её время (отложенное исполнение). Система работает отлично до того момента, пока нам вдруг не вздумается уничтожить поток геймспая (например, выход из программы). Вот тут начинаются проблемы - ведь в этот момент уже могли поступить необработанные запросы на отложенные действия - их приходится уничтожать, не выполняя. Но и это еще не всё - пока мы производим всё это уничтожение - приходят новые запросы, а об этом мы не узнаем пока не выйдем из текущей критической секции (без этого мы не получим потоковую безопасность). Когда мы выйдем из критической секции - объект, выполняющий отложенные операции будет уничтожен, а новые запросы по прежнему идут. Тут всё и накрывается медным тазом.

Вывод - всё сложно и подходить к этому всему надо весьма аккуратно.
#7
07.05.08 18:04
0
Mirage
Ну допустим, выражаются то они в большинстве случаев одинаково - AV или зависание :) Но вот ловить их - это уже весело.
#9
08.05.08 15:40
0
короче я понял если делать, то делать так что бы один и тот же объект не использовался в разных потоках, а то это приведёт не к неисправимому...
всем СПАСИБО))))

PS XProger - так я и прошу чтоб не посылали)))
Отредактировано: 08.05.08 15:47
#10
Почётный лектор
08.05.08 15:42
0
Цитата(lans @ Сегодня, 11:40)
[snapback]79881[/snapback]
делать так что бы один и тот же объект не использовался в рахных потоках

Неправильно. Так, чтобы не использовался в разных потоках одноврмененно. Если потоки друг с другом никак не связаны, то ты не сможешь ими управлять и они станут бесполезными.
#11
28.05.08 02:12
0
а можно так что бы есть к примеру класс
TMyObject = class
arr: array of array of procedure
procedure draw;
procedure update;
end;
//короче и там и там используется этот массив
и если создать два потока(первый для апдейта второй для рендера) проблем не будет?
#12
28.05.08 02:40
0
lans
"arr: array of array of procedure" - манъиаг. вопроса не понял, но проблеммы всё равно будут.
#13
аксакал
28.05.08 03:57
0
lans
Будут если не синхронизировать работу с массивом между потоками.
#14
28.05.08 12:35
0
Проблем можно избежать, если прислушаться к XProger, а точнее:
1) все обращения к массиву должны быть вынесены в отдельные процедуры, являющиеся членами класса TMyObject, соответственно сам массив должен быть недоступен даже наследникам, только функции для работы с ним.
2) класс должен содержать критическую секцию (TRTLCriticalSection), желательно так же недоступную наследникам.
3) тело функции должно быть примерно таким (писал тут, мог чуть-чуть ошибиться в синтаксисе):
Код
procedre TMyObject.some;
begin
  EnterCriticalSection(@FSection);
  try
    { some code }
  finally
    LeaveCriticalSection(@FSection);
  end;
end;
#15
28.05.08 13:38
0
Drakoзачем она нужна?
#16
28.05.08 15:18
0
Цитата
зачем она нужна?

Чтобы при вызове методов класса из разных потоков не было одновременного обращения к одним и тем же ресурсам. В случае использования критических секций второй (третий, n-й) вызов просто будет ожидать пока первый не закончит работы с данным ресурсом. Отсюда: код заключенный в EnterCriticalSection - LeaveCriticalSection должен выполняться максимально быстро.
#17
28.05.08 15:24
0
У меня даже класс такой простенький есть..

Код

{
  R-Age Common Units Library

  @author (Woolf)
  @created(31.07.2007)
  @lastmod(31.07.2007)

  (C) R-Age cl.
}
unit UThreadLocker;

interface
uses Windows, Classes;

{.$DEFINE DEBUG_LOCK}

type
   TThreadLocker = class(TObject)
   private
      FLock: TRTLCriticalSection;

      {$IFDEF DEBUG_LOCK}
      procedure OutputDebug(const aCallName: string);
      {$ENDIF}

   public
      constructor Create();

      destructor Destroy(); override;

    { lock queue for thread safe execution }
      procedure Lock();

    { unlock queue }
      procedure Unlock();
   end;

////////////////////////////////////////////////////////////////////////
implementation
uses SysUtils;

{ TThreadLocker }

{************************************************************************}

constructor TThreadLocker.Create();
begin
   inherited Create();

   InitializeCriticalSection(FLock);
end;

{************************************************************************}

destructor TThreadLocker.Destroy();
begin
   Unlock();
   DeleteCriticalSection(FLock);
   inherited Destroy;
end;

{************************************************************************}

procedure TThreadLocker.Lock();
begin
   {$IFDEF DEBUG_LOCK}
   OutputDebug('Lock - Enter');
   {$ENDIF}
   EnterCriticalSection(FLock);
   {$IFDEF DEBUG_LOCK}
   OutputDebug('Lock - Leave');
   {$ENDIF}
end;

procedure TThreadLocker.Unlock();
begin
   {$IFDEF DEBUG_LOCK}
   OutputDebug('Unlock - Enter');
   {$ENDIF}
   LeaveCriticalSection(FLock);
   {$IFDEF DEBUG_LOCK}
   OutputDebug('Unlock - Leave');
   {$ENDIF}
end;

{************************************************************************}

{$IFDEF DEBUG_LOCK}
procedure TThreadLocker.OutputDebug(const aCallName: string);
var
   str: string;
begin
   str := Format('[%d]TThreadLocker.%s',
      [GetCurrentThreadId(), aCallName]);
   OutputDebugString(PChar(str));
end;
{$ENDIF}



end.




Юзается просто..

Код


var ThLock:TThreadLocker;
...
constructor ...
ThLock:=TThreadLocker.create;

destructor
ThLock.Free;

Your code:

ThLock.lock;
try
  
  //Работа с потокоопасными ресурсами

finally
  ThLock.Unlock;
end;





#18
29.05.08 14:14
0
спасибо всем, теперь буду думать делать или нет))))
#{{post.Index}}
{{post.Author.Login}}
{{post.CreatedDate | date:'dd.MM.yy HH:mm'}}
{{post.VotesRating}}
Отредактировано: {{post.UpdatedDate | date:'dd.MM.yy HH:mm'}}