Конференция "Начинающим" » Локальный массив процедуры/функции
 
  • dmk © (09.06.17 09:49) [0]
    В процедуре определен массив, размер заранее которого неизвестен.
    Т.е. MAX известен только после запуска.
    Компилятор хочет видеть MAX как константу.
    Можно ли как нибудь MAX сделать как переменную, т.е. обойти это ограничение?
    Глобальным массив сделать нет возможности. Такое условие.

    procedure DoSomething;
    var
     A: array[0..MAX] of integer;

    begin
     //Что-нибудь делаем с масссивом
    end;

  • SergP © (09.06.17 10:14) [1]
    Может ты хочешь что-то такое:


    > procedure DoSomething;
    > var
    >  A: array of integer;
    >
    > begin
    > setlength(A,MAX+1);
    >
    >  //Что-нибудь делаем с масссивом
    > end;


    ?
  • dmk © (09.06.17 12:57) [2]
    SetLength исключен. Очень медленно каждый раз определять размер.
    Что-нибудь в секции Initialization при запуске подойдет.

    Assignable constants в определении массива не работает тоже к сожалению :(
  • SergP © (09.06.17 14:19) [3]

    > Что-нибудь в секции Initialization при запуске подойдет.


    Т.е. ты хочешь все-таки использовать массив, которому память будет выделяться в стеке?
    Хз. не пробовал, но теоретически можно попробовать сделать.  Но в секции Initialization тогда придется изменять код самой процедуры, а точнее придется менять литералы в некоторых командах работы с указателем стека.
    Для этого придется сначала посмотреть, что представляет собой скомпилированный код процедуры и найти там эти команды.

    Но это все ИМХО...
  • Sha © (09.06.17 14:41) [4]
    > dmk ©   (09.06.17 12:57) [2]
    > SetLength исключен. Очень медленно каждый раз определять размер.
    > Что-нибудь в секции Initialization при запуске подойдет.

    SetLength глобального массива в секции Initialization
  • dmk © (09.06.17 14:46) [5]
    >глобального массива
    Нельзя. Для потокобезопасности используются только локальные.
    С глобальными вообще всю логику придется переписывать.
  • SergP © (09.06.17 14:55) [6]
    Хм. попробовал так (хотел чтобы на самом деле выделялось :
    procedure eee;
    var
    a:array[0..30] of integer;
    begin
    a[5]:=155;
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    eee;
    end;

    initialization
    //Пытаемся сделать чтобы на самом деле массиву в процедуре eee выделялось 11 элементов, а не 31
    PByte(cardinal(@eee)+2)^:=$d4;
    PByte(cardinal(@eee)+13)^:=$2c;


    Но оно так не хочет работать. Вываливается AV
  • Sha © (09.06.17 15:07) [7]
    >dmk ©   (09.06.17 14:46) [5]
    >> глобального массива
    > Нельзя. Для потокобезопасности используются только локальные.

    тогда можно создавать в вызывающей процедуре и передавать параметром
  • dmk © (09.06.17 15:20) [8]
    >передавать параметром
    Константу хочет :(
  • dmk © (09.06.17 15:29) [9]
    Тут история запутанная. Это процедура класса. Получается, что параметром надо передавать указатель на массив инициализированный например при создании потоков.
    А номер потока тоже получается передавать надо? Типа какой поток вызвал эту функцию!?
    А на самом деле эта величина вариативная и зависит от Y-разрешения экрана.
    Я поставил константу 2700 с учетом максимального разрешения стандарта 5K, но тут вдруг вики мне сказала, что уже 8K есть. Поэтому хочется переменную.
    Если у меня 20 ядер, то это получается надо 20 массивов глобальных обрабатывать, а локальный автоматом распараллеливается.
  • SergP © (09.06.17 15:59) [10]
    8к*20 - это не так то и много с точки зрения экономии памяти, так что можно даже поставить со значительным запасом.

    А то пробовал поиграться с ассемблером (попытки делания ассемблерных вставок в процедуру в которых меняется esp и ebp), но компилятор в таких случаях добавляет свой код, который все портит.

    Так что ситуация получается похожа на цитату Бисмарка: Никогда ничего не замышляйте против компилятора, на каждую Вашу хитрость он ответит своей непредсказуемой глупостью.
  • dmk © (09.06.17 16:29) [11]
    3 Мб на процедуру в конфигурации 2-х 24 ядерных Xeon'ов.
    В принципе не так уж и много. Правда есть Xeon Phi. Там уже по сотне с лишним процессоров. Самый простой Xeon Phi уже 9 Мб на процедуру будет кушать.
  • rrrrrr © (09.06.17 16:47) [12]
    будешь долго и больно страдать с массивом или просто сделаешь гетмем(x * SizeOf(Integer)) + PInteger ?
  • sniknik © (09.06.17 16:53) [13]
    стек вообще то гораздо меньше чем оперативная память, поэтому непонятно зачем пихать туда массив, вместо простого динамического (в стеке указатель). в причинах ссылка на многопотоковость... но стек то один, и много параллельных вызовов с такой архитектурой просто не влезет.
  • Sha © (09.06.17 16:58) [14]
    > Константу хочет :(

    так параметром не размер передавать, а var-массив
     

    > Тут история запутанная. Это процедура класса.

    тогда сделай массив полем класса потока и создавай нужного размера при создании потока
  • dmk © (09.06.17 17:28) [15]
    >тогда сделай массив полем класса потока
    Непотокобезопасно. Только локальный :(
  • dmk © (09.06.17 17:28) [16]
    rrrrrr ©   (09.06.17 16:47) [12]
    Это процедуры отрисовки. GetMem тормоз.
  • SergP © (09.06.17 17:38) [17]
    Ну можно попробовать целиком процедуру на ассемблере переписать
  • NoUser © (09.06.17 18:38) [18]
    > sniknik ©   (09.06.17 16:53) [13]> но стек то один, и много параллельных вызовов с такой архитектурой  просто не влезет.
    не понял, про 'один' ? мегабайт ?

    dmk,
    http://pda.delphimaster.net/?id=1465627000&n=3&p=2 (21,23..25)
  • han_malign © (09.06.17 19:29) [19]

    > Непотокобезопасно. Только локальный :(

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


    procedure call64K();
    var buf[0..65535]of byte;
    begin
        call_(buf, sizeof(buf));
    end;
    ........................
    case HighBitNumber(maxSize shr 16) of
    0: call64K();
    1: call128K();
    2: call256K();
    ...
    15: call4G();
    end;

  • rrrrrr © (09.06.17 19:29) [20]
    Это процедуры отрисовки. GetMem тормоз.

    а массив типа это газ.
  • Sha © (09.06.17 19:37) [21]
    >> тогда сделай массив полем класса потока
    > Непотокобезопасно. Только локальный :(

    ???
    В каждом потоке использовать поле класса потока небезопасно???
    Это если только лезть к нему из 1000 других потоков, кроме одного потока-владельца.
  • SergP © (09.06.17 21:44) [22]
    Во. А если сделать так:


    var
     Form1: TForm1;
     MAX:integer;
     Bytelen:integer;

    implementation

    {$R *.dfm}

    procedure proc(var A:array of integer);
    begin
    a[12]:=555;
    showmessage(inttostr(a[12]));
    end;

    procedure DoSomething;
    asm
     sub esp,Bytelen
     mov eax,esp
     mov edx,MAX
     call proc
     add esp,Bytelen
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
     DoSomething;
    end;

    initialization
    MAX:=40;
    Bytelen:=(MAX+1)*sizeof(integer);

    end.


    ?
    Так вроде должно работать.
  • Sha © (09.06.17 21:56) [23]
    > SergP ©   (09.06.17 21:44) [22]

    Все несколько сложнее,
    см. реализацию этой идеи в исходниках (искать что-то вроде StackAlloc)
  • dmk © (09.06.17 22:11) [24]
    Проще использовать один глобальный массив, а в процедуру передвать линейный адрес смещения в массиве.
  • dmk © (09.06.17 22:15) [25]
    >по умолчанию под потоковый стек выделяется всего один мегабайт
    У меня пока локальный массив 10,54 Кб. Для 5K хватит.
    20,48 Кб для 8K, но я пока таких мониторов не видел.
  • Inovet © (15.06.17 09:48) [26]
    > [25] dmk ©   (09.06.17 22:15)
    > но я пока таких мониторов не видел

    Мониторов может быть много, так что не надо на разрешение завязываться. Про поле класса потока ты, похоже, не то что-то понял.
  • QAZ (15.06.17 18:54) [27]
    threadvar
 
Конференция "Начинающим" » Локальный массив процедуры/функции
Есть новые Нет новых   [118451   +43][b:0][p:0.001]