Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > указатель на массив


Автор: leg501 7.7.2008, 10:42
Сдраствуйте господа. есть такая проблемка 
1)есть поток в нем есть массив его содержимое изменяет функция 
2)есть второй поток который должен выцеплять данные по не которому условию из этого массива (условие цеплять или нет)))
пробую писать так

поток которы й выцепляет
Код

WriteThread = class(TThread)
public
Buffer :array of SHORT ;
Buffer2:^SHORT;
Half:^bool;
constructor TWriteThread.Create( AdcBuffer :^SHORT;Half_Ready:bool;)
end;
implementation
constructor TWriteThread.Create( AdcBuffer :^SHORT;Half_Ready:bool;)
begin
Inherited Create(false);

self.Buffer:= @AdcBuffer;  / / а в данном могу но что то не те данные
self.Buffer2:= @AdcBuffer;// в данном случае обратится к массиву немогу (простое присвоение без @ компилятор не пропускает) 
self.Half:=@Half_Read;
end;

procedure TWriteThread.Execute;
var
t:double;i:integer;
begin
while Half^ do                         
                         begin
                                t:=t+ Buffer[i] ;
                                i:=i+16;
                        end;
                          Form1.Edit1.Text := FormatFloat('0.#####',1000/8000* (t/E440_Size) );
                          i:=0;t:=0;
                  end;
end;
end.


поток изменения масива
Код

TThreadE= class( TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
    public
Buffer :array[0..35000] of SHORT ;
Half_Ready:bool;
DataStep:word;
AdcBuffer:PSHORT;
procedure ReadData(Buffer:array of SHORT;DataStep:word);
  end;

implementation
procedure asd.Execute();
var
i:integer;
begin
AdcBuffer:=@Buffer[0];
i:=0;
for i:=0 to 100000 do
ReadData(Buffer,DataStep);
end;

procedure asd.ReadData(Buffer:array of SHORT;DataStep:word);//íà ñàìîì äåëå íåâàæíî ÷òòî ïðîèñõîäèò â ýòîé ïðîöåäóðå
var i:integer;
begin
i:=0 ;
for i:=0 to DataStep do
Buffer[i]:=DataStep+i;
end;
end.

собственно задача сводится к большему но ключевой момент это доступ к массиву из другого места(модуля\потока)
пробывал var  параметр на массив но что то переопределенный конструктор нехочет

Автор: Virtuals 7.7.2008, 13:27
несколько основных моментов:
1. буфер данных при использовании в разных потоках обьявляется снаружи тоесть (кстати в обьявлении у вас ошибка  smile )нужно так

Код

type
TBuffer = array of SHORT ;
PBuffer = ^TBuffer;


var
Buffer :PBuffer; //!!!

...

WriteThread = class(TThread)
...
constructor TWriteThread.Create( AdcBuffer :PBuffer)

end;

TThreadE= class( TThread)
...
end;


2. инициализировать буфер ДО старта потоков

3. далее доступ к данным в Buffer из обоих потоков ТОЛЬКО через метод Synchronize!!!

4. ну и как пользовать

Код

program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
TBuffer = array[0..1] of integer ;
PBuffer = ^TBuffer;
var
Buffer :PBuffer; //!!!

  begin
  { TODO -oUser -cConsole Main : Insert code here }
GetMem(Buffer, SizeOF(TBuffer));

  writeln('Hello');
  Buffer^[0]:=1010;  Buffer^[1]:=11;
  writeln(  Buffer^[1]);
  writeln(  Buffer^[0]);
      FreeMem(Buffer);
  readln;

end.





Автор: leg501 7.7.2008, 13:50
Тоесть вы предлагаете иползовать глобальный массив для обоих потоков ,но тогда зачем нужно будет вызов данных через указатель , я ведь и так смогу обратится напрямую с массиву или я неправ.

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

Автор: Virtuals 7.7.2008, 21:17
leg501, 
ну еще раз!

А. данные используемые в разных потоках, ну просто обязанны быть снаружи!
Б. соответственно память под эти данные обязана быть выделенной до, использования ее в потоке
В. требуется исключить любую возможность асинхронного доступа к данным из разных потоков (имелось ввиду что один поток пишет вторую половину данных, в то врея когда другой читает первую половинку,- упрощенный пример, а еще хуже когда 2 потока пытаются заисать в одну и ту же область) просто почитайте про Synchronize, думаю станет поятно зачем это
//идио... пример:
поток 1 записал в буфер: "маша дэфка"
поток 2 читает буфер "маша"
поток 1 пишет в буфер "петя пасан"
поток 2 дочитывает буфер " пасан"
итог:
у поток 2 буфер = "маша пасан" smile  smile

Добавлено через 3 минуты и 59 секунд
а вызов через указатель- а его почти всегда можно передать, в отличии от чего другого, + можн память выделять ка изнутри, так и извне

/ну типа: слыш процедур, пишика по этому адресу, в том формате, о котором мы с тобой вкурсе/ smile  smile  smile

Добавлено через 13 минут и 1 секунду
leg501,  а вот насчет указателей, есть способы читать любое смещение относительно адреса, а вот по сравнению с C  как вам такое
Код

var
mlia : word;
miaPoByte: array [0..1] of byte absolute mlia;

 smile 

Автор: Beltar 8.7.2008, 08:13
Через типизированный указатель в Delphi еще лучше чем на плюсах, можно к указателю применить Inc и Dec и это будет смещать его на размер базового типа. Ну или всякие преобразования указателя к целому.
Впрочем если есть массив, то что мешает обращаться к нему просто по индексам?

А Synchronize по-моему нужен для работы с визуальными компонентами, в принципе всегда можно применить блокировку, так чтобы работал с буфером только поток ее установивший.

Автор: Virtuals 8.7.2008, 09:36
Цитата(Beltar @  8.7.2008,  08:13 Найти цитируемый пост)
А Synchronize по-моему нужен для работы с визуальными компонентами, в принципе всегда можно применить блокировку, так чтобы работал с буфером только поток ее установивший.


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

в принципе всегда можно применить блокировку, так чтобы работал с буфером только поток ее установивший. - 
все правильно но!!! флаг блокировки взводить и проверять только через Synchronize (в частном случае)
Synchronize - заставляет "вынырнуть" из потока, в поток родитель!

ЗЫ в своих приложениях всегда стараюсь пользовать Synchronize, это дает достаточно простой способ, не наступить на грабли с доступом к данным при межпоточном взаимодействии!


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

program useUkazatel;

{$APPTYPE CONSOLE}

uses
  SysUtils;
const AAZ:string =#01+#02+#03;

type
TBuffer = array of Byte ;
PBuffer = ^TBuffer;
var
xBuffer :TBuffer;
PxBuffer :PBuffer; //!!!

  begin
  { TODO -oUser -cConsole Main : Insert code here }
GetMem(xBuffer, 32);
PxBuffer :=@xBuffer;

  writeln('Hello');
  PxBuffer^[1]:=10;
  PxBuffer^[2]:=11;
  PxBuffer^[3]:=12;
  PxBuffer^[4]:=13;
  writeln(  PxBuffer^[1]);
  writeln(  PxBuffer^[2]);
  PxBuffer:= pointer(@AAZ);
  writeln(  PxBuffer^[1]);
  writeln(  PxBuffer^[2]);
      FreeMem(xBuffer);
      PxBuffer:=nil;
  readln;

end.

Автор: Rrader 8.7.2008, 18:09
Цитата(Beltar @  8.7.2008,  15:13 Найти цитируемый пост)
А Synchronize по-моему нужен для работы с визуальными компонентами

В методе, вызываемом с помощью Synchronize, может быть любой код, в том числе и потоко-небезопасный код VCL.

Synchronize - это просто удобное средство синхронизации. Синхронизировать VCL с помощью обычных методик тяжело. Но за все следует платить - вызовы Synchronize увеличивают нагрузку на основной поток.

Virtuals, в подобного рода задачах (асинхронный доступ к данным из разных потоков, не работающих с VCL) использовать Synchronize совершенно неэффективно. Не стоит использовать сложные методы синхронизации там, где этого не нужно. Достаточно обойтись критической секцией и получить максимальную производительность.

Код

InitializeCriticalSection(CS);
try
  { Lock }
  EnterCriticalSection(CS);
  try
    // Работа с ресурсом
  finally
    { Unlock }
    LeaveCriticalSection(CS);
  end;
finally
  DeleteCriticalSection(CS);
end;


Автор: Virtuals 9.7.2008, 06:00
Rrader, 
unit Classes;
ничего не напоминает?
 smile 

Код


procedure TThread.Synchronize(Method: TThreadMethod);
var
  SyncProc: TSyncProc;
begin
{$IFDEF MSWINDOWS}
  SyncProc.Signal := CreateEvent(nil, True, False, nil);
  try
{$ENDIF}
{$IFDEF LINUX}
    FillChar(SyncProc, SizeOf(SyncProc), 0);  // This also initializes the cond_var
{$ENDIF}
    EnterCriticalSection(ThreadLock);
    try
      FSynchronizeException := nil;
      FMethod := Method;
      SyncProc.Thread := Self;
      SyncList.Add(@SyncProc);
      ProcPosted := True;
      if Assigned(WakeMainThread) then
        WakeMainThread(Self);
{$IFDEF MSWINDOWS}
      LeaveCriticalSection(ThreadLock);
      try
        WaitForSingleObject(SyncProc.Signal, INFINITE);
      finally
        EnterCriticalSection(ThreadLock);
      end;
{$ENDIF}
{$IFDEF LINUX}
      pthread_cond_wait(SyncProc.Signal, ThreadLock);
{$ENDIF}
    finally
      LeaveCriticalSection(ThreadLock);
    end;
{$IFDEF MSWINDOWS}
  finally
    CloseHandle(SyncProc.Signal);
  end;
{$ENDIF}
  if Assigned(FSynchronizeException) then raise FSynchronizeException;
end;


не спорю что просто критическая секция помогает и значительно быстрее, но увы не всегда поймеш где нарвешся на проблемы, а вот SyncProc.Signal использовать это один из простых, хоть и медленных способов, так зачем изобретать велосипед, в большинстве случаев достаточно и производительности Synchronize

Автор: Rrader 10.7.2008, 04:13
Цитата

но увы не всегда поймеш где нарвешся на проблемы

В данной задаче не нарвешься. Нужно строить эффективный код, когда эта возможность и так на блюдечке smile 

Автор: leg501 10.7.2008, 08:35
Спасибо за повторное обьяснение и привидение примеров так сказать на пальцах это помогло представить задачу немного в другом свете и решить таки ее .
Доступ к данным через указатель и смещение его inc и dec оказалось не так удобно как глобальный масив ю
Чтож бдем учится языку и его фитчам незря же люди есть готовые помочь начинающим.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)