Autor Téma: Změna velikosti pole přes ukazatel ve vláknu - podivné chování  (Přečteno 610 krát)

Offline age.new

  • Hrdina
  • ****
  • Příspěvků: 255
  • Karma: 0
Vážená komunito,

narazil jsem na zvláštní chování dynamického pole, jehož velikost měním ve vláknu, které se na něj odkazuje přes ukazatel. Pro lepší pochopení:

type
  TArrayString = array of string;
  PArrayString = ^TArrayString;
...
pole: TArrayString;
...

Vlákno při jeho vytvoření dostane ukazatel (PArrayString) na pole (Vlakno.Create(@pole)). V Execute části se pole zvětšuje a plní. Zde v debug okně vidím, že je vše v pořádku. Zvětšování a plnění je vše s operátorem ^.

Na konci Execute části vlákna mám Synchronize s procedurou, která dále pracuje s polem (ale né již s ukazatelem, protože tato volaná procedura je v hlavním vlákně. Zde ovšem v debug okně vidím, že pole je prázdné.

Proč se to děje? Jakoby se pole měnilo jen lokálně a po skončení vlákna se vrátilo do původní velikosti, tj. do 0. Domníval jsem se, že přes ukazatele přistupuji přímo na proměnou pole a že tak i s ní pracuje "napřímo".

Kde může být chyba?

Děkuji.


Offline starous

  • Mladík
  • **
  • Příspěvků: 94
  • Karma: 2
    • Verze Delphi: Delphi 7, Delphi 10.4
Zkusil bych použít TStringList. Tam bude asi problém s přealokací toho pole na jiné místo při jeho dynamickém zvětšování.

Offline < z >

  • Administrátoři
  • Guru
  • *****
  • Příspěvků: 1156
  • Karma: 44
    • Verze Delphi: 7, 2010
Základní otázka - jak vytváříš to pole a jak a kdy se uvolňuje ...

Offline age.new

  • Hrdina
  • ****
  • Příspěvků: 255
  • Karma: 0
je to obyčejné pole, takže na začátku je SetLength(pole^, 0); a přidávám položky stejným způsobem přes SetLength. V rámci vlákna a jeho Execute procedury vidím, jak se pole zvětšuje a plní v pořádku. Jakmile ale Execute skončí, resp. na jeho konci si přes Synchronize zavolám proceduru v hlavním vláknu, tak ta vidí to samé pole prázdné. Nejde mi to moc do hlavy proč.

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 3119
  • Karma: 136
    • Verze Delphi: D2007, XE3, DX10
Nejde mi to moc do hlavy proč.
Pole je pointer na kus pameti na heapu, ktera se pri kazde zmene velikosti pole realokuje = hodnota pointeru se meni. Takze predani adresy te promenne a jeji dereference neni v principu spatne, takze nekde musi delat neco, co spatne je.

V bubaku zastav na vhodnem miste, zobraz si pohled na CPU a podivej se na adresu te promenne, ktera to pole obsahuje. No a pak tu hodnotu v ruznych fazich zpracovani v tom okne konfrontuj. To nemuze byt slozite najit.

Ale jak jsme tu nedavno diskutovali, pokud se meni pocet polozek v datove strukture, je lepe pole nepouzit a jak psal starous treba seznamem, protoze se s tim pracuje pres const pointer, realokace se deji vnitrne jen po skocich, ne po kazde zmene velikosti.
« Poslední změna: 23-10-2020, 08:36:10 od pf1957 »

Offline age.new

  • Hrdina
  • ****
  • Příspěvků: 255
  • Karma: 0
Tak jsem na to přišel. Ano, je to moje chyba, respektive práce vlákna s polem je správná, jen se prováděla se špatným polem. Vytvoření vlákna se volalo v proceduře, kam jsem předával pole s const parametrem a vláknu pak i tento parametr podsunul - což je špatně. Příklad:

procedure Delej(const pole: TArrayStrings);
begin
..
Vlakno := TThread.Create(@pole);  ... a zde je ta chyba. Adresa pole je jiná, než adresa skutečného pole. Ve vláknu jsou koukal na pole vytvořené procedurou Delej a mimo vlákno se díval na pole vytvořené v hlavním vláknu.
..
end;


Offline age.new

  • Hrdina
  • ****
  • Příspěvků: 255
  • Karma: 0
Nejde mi to moc do hlavy proč.
Pole je pointer na kus pameti na heapu, ktera se pri kazde zmene velikosti pole realokuje = hodnota pointeru se meni. Takze predani adresy te promenne a jeji dereference neni v principu spatne, takze nekde musi delat neco, co spatne je.

V bubaku zastav na vhodnem miste, zobraz si pohled na CPU a podivej se na adresu te promenne, ktera to pole obsahuje. No a pak tu hodnotu v ruznych fazich zpracovani v tom okne konfrontuj. To nemuze byt slozite najit.

Ale jak jsme tu nedavno diskutovali, pokud se meni pocet polozek v datove strukture, je lepe pole nepouzit a jak psal starous treba seznamem, protoze se s tim pracuje pres const pointer, realokace se deji vnitrne jen po skocich, ne po kazde zmene velikosti.

Seznam v Delphi osobně nepoužívám - nemám s ním moc zkušeností. Spojový seznam si raději opět tvořím sám. Pole jako takové se snadno upravuje bez nutnosti používat Create / Free a tak. Proto se mi nehodí ani TStringList a podobné.

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 3119
  • Karma: 136
    • Verze Delphi: D2007, XE3, DX10
Seznam v Delphi osobně nepoužívám - nemám s ním moc zkušeností. Spojový seznam si raději opět tvořím sám. Pole jako takové se snadno upravuje bez nutnosti používat Create / Free a tak. Proto se mi nehodí ani TStringList a podobné.
No to je hodne slaby argument: seznam jednou vytvoris, jednou zrusis, v tomto pripade treba pri konstrukci/destrukci formulare. A pak uz ho jen predavas jako const parametr. A hodnoty pridavas jen prostym volanim Add(), Insert() a rusis Delete() ev. v pripade TStringList aj., kde je ukladany dvojice string+object tak jejich varianty se sufixem Object.

Offline age.new

  • Hrdina
  • ****
  • Příspěvků: 255
  • Karma: 0
No to je hodne slaby argument: seznam jednou vytvoris, jednou zrusis, v tomto pripade treba pri konstrukci/destrukci formulare. A pak uz ho jen predavas jako const parametr. A hodnoty pridavas jen prostym volanim Add(), Insert() a rusis Delete() ev. v pripade TStringList aj., kde je ukladany dvojice string+object tak jejich varianty se sufixem Object.

Nemyslím to tak, že jsou špatné, jen v tomto případě jsou pro mě nevhodné. Pokud nepotřebuji ten obal okolo (funkce a další property jako TStrings aj.), tak nemusím řešit konstrukci/destrukci. Pokud je to pole součástí struktury, tak její vytváření / rušení je jednodušší (v mém případě).

Offline František

  • Guru
  • *****
  • Příspěvků: 623
  • Karma: 6
    • Verze Delphi: primárne v XE5, občas 10.2.3 comunity
ja by som už dnes použil TList<...>

Offline age.new

  • Hrdina
  • ****
  • Příspěvků: 255
  • Karma: 0
Re:Změna velikosti pole přes ukazatel ve vláknu - podivné chování
« Odpověď #10 kdy: 27-10-2020, 07:05:22 »
TList<...> je pro mě novinka, resp. ještě jsem jej neprogramoval.

Offline František

  • Guru
  • *****
  • Příspěvků: 623
  • Karma: 6
    • Verze Delphi: primárne v XE5, občas 10.2.3 comunity
Re:Změna velikosti pole přes ukazatel ve vláknu - podivné chování
« Odpověď #11 kdy: 02-11-2020, 11:41:33 »
tiež to bola pre mňa ešte nedávno novinka, ale teraz už žiadny array ...