Хакнуть динамический массив?

Обсуждаются как существующие проекты (перевод документации, информационная система и т.п.), так и создание новых.

Модератор: Модераторы

Re: Хакнуть динамический массив?

Сообщение hinst » 18.03.2014 17:47:58

я рассуждаю о тяжёлых буднях самого себя, когда у меня некоторые объекты используются сразу во многих местах, и я не хочу думать, как их лучше освободить, я хочу, чтобы они освободились, как только последний указатель на них вышел из области видимости

Добавлено спустя 3 минуты 20 секунд:
Либо чтобы было "всё само", но это слишком как-то сложно реализовать
Либо чтобы я вызывал AddRef & Release сам, ведь Create и Free я и так уже вызываю, так что увеличение сложности тут будет не большое (хотя некоторое всё же будет)

Добавлено спустя 3 минуты 49 секунд:
Я думаю, что Хакнуть динамический массив - это как раз один из возможных подходов сделать всё само, вот я и думаю, в том числе, как бы это сделать

Добавлено спустя 5 минут 2 секунды:
Надо только присобачить туда свой деструктор

Добавлено спустя 14 секунд:
ну или не знаю, как это сработает на практике
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Хакнуть динамический массив?

Сообщение скалогрыз » 18.03.2014 18:02:30

hinst писал(а):Я думаю, что Хакнуть динамический массив - это как раз один из возможных подходов сделать всё само, вот я и думаю, в том числе, как бы это сделать

переписать компилятор, очевидно :)

Если ты ищешь "решения", то нужно думать, что "хак" не является "решением". Т.к. "хак" - обход правил, костыли, затычки. Надеюсь, намёк ясен ;)

С освобождением динамических массивов/строк, при использовании потоков, всё не так очевидно, и не так гладко. Ибо операции переопредления не являются потоко безопасными. Т.е. расчитывать на автоматизм здесь - только себе вредить.
Вызывай явно AddRef / Release и не ошибёшься никогда, потому что твой код - что хочешь, то и делаешь.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Хакнуть динамический массив?

Сообщение hinst » 18.03.2014 18:45:48

Создал вариант модуля для того, чтобы прикрутить подсчёт ссылок к любому классу, не меняя сам класс:
Код: Выделить всё
unit PSHO_GSharedU;

{$Mode ObjFPC}
{$LongStrings ON}   

interface

uses
  Classes, sysutils;

type

  { TGSharedObjectBase }

  TGSharedObjectBase = object
  protected
    FValue: TObject;
  public
    property V: TObject read FValue write FValue;
  protected
    FLocker: TRTLCriticalSection;
  public
    property Locker: TRTLCriticalSection read FLocker write FLocker;
  protected
    FCount: PInteger;
  protected
    property Count: PInteger read FCount write FCount;
  public
    procedure Init(a: TObject);
  public
    procedure Take;
  public
    procedure Drop;
  public
    procedure Release;
  public
    procedure Take(a: TGSharedObjectBase);
  end;

  { TGSharedObject }

  generic TGSharedObject<T> = object(TGSharedObjectBase)
  public
    procedure Init(a: TObject);
  protected
    function GetValue: T;
  protected
    procedure SetValue(a: T);
  public
    property V: T read GetValue write SetValue;
  end;

var
  DebugOutputEnabled: Boolean;

implementation

{ TGSharedObjectBase }

procedure TGSharedObjectBase.Init(a: TObject);
begin
  V := a;
  if V <> nil then
  begin
    InitCriticalSection(FLocker);
    Count := New(PInteger);
    Count^ := 0;
  end;
end;

procedure TGSharedObjectBase.Take;
begin
  EnterCriticalsection(FLocker);
  Inc(Count^);
  LeaveCriticalsection(FLocker);
end;

procedure TGSharedObjectBase.Drop;
var
  shouldRelease: Boolean;
begin
  if V <> nil then
  begin
    EnterCriticalsection(FLocker);
    Dec(Count^);
    shouldRelease := Count^ <= 0;
    LeaveCriticalsection(FLocker);
    if shouldRelease then
      Release;
  end;
end;

procedure TGSharedObjectBase.Release;
begin
  V.Free;
  V := nil;
  DoneCriticalsection(FLocker);
  Dispose(Count);
end;

procedure TGSharedObjectBase.Take(a: TGSharedObjectBase);
begin
  Drop;
  V := a.V;
  Locker := a.Locker;
  Count := a.Count;
  Take;
end;

{ TGSharedObject }

function TGSharedObject.GetValue: T;
begin
  result := T(FValue);
end;

procedure TGSharedObject.SetValue(a: T);
begin
  FValue := a;
end;

procedure TGSharedObject.Init(a: TObject);
begin
  inherited Init(a);
end;

end.


Код: Выделить всё
unit PSHO_SharedClassesU;

{$Mode ObjFPC}
{$LongStrings ON}

interface

uses
  Classes, PSHO_GSharedU;

type
  TSharedStrings = specialize TGSharedObject<TStrings>;

implementation

end.


Код: Выделить всё
program TestGShared;

{$Mode ObjFPC}
{$LongStrings ON}

uses
  sysutils,
  dateutils,
  Classes,
  PSHO_GSharedU, PSHO_SharedClassesU;

const
  ObjectCount = 1000000;

var
  x: array of TSharedStrings;
  m: TSharedStrings;
  time: TDateTime;
  i: Integer;

begin
  time := Now;
  SetLength(x, ObjectCount);
  for i := 0 to ObjectCount - 1 do
  begin
    x[i].Init(TStringList.Create);
    x[i].Take;
    m.Init(nil);
    m.Take(x[i]);
    m.Drop;
  end;
  for i := 0 to ObjectCount - 1 do
  begin
    x[i].Drop;
  end;
  WriteLN(MilliSecondsBetween(Now, time));
end.


Вроде бы, не плохо работает.

Что я заметил: с TRTLCriticalSection работает примерно в 2 раза быстрее, чем с TCriticalSection

Контейнер "приматывается" к существующему классу такой конструкцией:
Код: Выделить всё
TSharedStrings = specialize TGSharedObject<TStrings>;

Далее доступ к нему через поле V:
Код: Выделить всё
sharedStrings.V.Add('Meow');


Принцип работы такой, что эти контейнеры можно присваивать: Count это Pointer, TRTLCriticalSection по сути тоже, V - тоже, поэтому если присваиванием создать множество копий shared-объекта, у них у всех будут указатели на одну и ту же критическую секцию, один и тот же объект, один и тот же Count
Увеличение и уменьшение счётчика методами Take, Drop.
Копирование:
Код: Выделить всё
   
    x2 := x1;
    x2.Take;

Для наглядности можно будет сделать метод TakeCopy:
Код: Выделить всё
   
    x2 := x1.TakeCopy;
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Хакнуть динамический массив?

Сообщение Mirage » 18.03.2014 21:13:02

hinst писал(а):я рассуждаю о тяжёлых буднях самого себя, когда у меня некоторые объекты используются сразу во многих местах, и я не хочу думать, как их лучше освободить, я хочу, чтобы они освободились, как только последний указатель на них вышел из области видимости


А если два объекта друг на друга ссылаются? :lol:

Объекты, в рамках рассматриваемой задачи, можно поделить на две категории:
1. Временные и короткоживущие в рамках определенной области (например, процедуры). Их много, некоторые требуют правильной финализации и т.п. Действительно много мороки. Для них решение в топике есть.
2. Долгоиграющие. Часто непосредственно связаны с предметной областью и все такое. Вот жизненный цикл таких объектов отдавать на откуп автоматике, да еще такой несовершенной как подсчет ссылок, я бы не стал. Жизненный цикл таких объектов должен контролироваться осмысленно и централизованно, в соответствии с этой самой предметной областью. Пример - хотя бы VCL.
Наличие большого количества объектов, не попадающих ни в одну из категорий, т.е. по сути временных и при этом гуляющих где вздумается, вероятно сигнализирует о плохой архитектуре. В многопоточной среде они очень быстро приведут приложение к непотребному состоянию.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Хакнуть динамический массив?

Сообщение hinst » 19.03.2014 21:47:46

нет в жизни совершенства в общем
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Пред.

Вернуться в Разное

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 10

Рейтинг@Mail.ru