Forum Delphi.cz

Win32 a Win64 => Obecné => Téma založeno: Hdm 22-04-2013, 08:22:06

Název: predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: Hdm 22-04-2013, 08:22:06
Ahoj,
mám program napsaný v Delphi a jednou funkcí je ukládání do souboru s koncovkou html.
Všude to funguje(rúzné verze windows včetně Win7profi), problém je pouze na sestavě:
HP minitower 8100 s předinstalovým Windows 7 profi 32bit i 64bit (přesnější popis stroje zákazník zatím nedodal)
Na stroji je prý nainstalovaný různý HP pomocný SW
Soubor to do umístění nevytvoří/neuloží a program žádnou chybu nehlásí, přestože je ukládání v chráněné části kódu. Toto by mohlo taky znamenat, že soubor vytvoří, ale hned ho něco smázne.
Soubory s koncovkami TXT, LOG, INI to vytvoří bez problémů.

Zkoušeli jsme:

Nemáte někdo nějakou zkušenost s podobným problémem a jak to vyřešit?. Řešení ve smyslu nainstalovat tam čistý OS z CD a ne z HP backup oblast zákazník moc nevítá.i
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: pf1957 22-04-2013, 08:54:30
Soubor to do umístění nevytvoří/neuloží a program žádnou chybu nehlásí, přestože je ukládání v chráněné části kódu. Toto by mohlo taky znamenat, že soubor vytvoří, ale hned ho něco smázne.
A FileMon na to rika co?
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: Hdm 15-05-2013, 13:38:15
Pokročil jsem ve zkoumání problému.
Jde o ukládání TstringList.SaveToFile z vedlejšího vlákna. Zkoušel jsem přesně toto ukládání obalit kritickou sekcí, ale nepomohlo.
Uložení z hlavního vlákna proběhne v pořádku, ale ten samý TstringList se uloží prázdný(to co naplnilo vedlejší vlákno tam není)

Kód: [Vybrat]
      ...
      EnterCriticalSection(tmpLock);
      try
        SL.SaveToFile(ExtractFilePath(ParamStr(0)) + SL_Name);
      except
        on E : Exception do
        begin
          WriteToLog(E.ClassName + ' - ' + E.Message);
        end;
      end;         
      LeaveCriticalSection(tmpLock);
      ...
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: pf1957 15-05-2013, 14:13:57
Pokročil jsem ve zkoumání problému.
Jde o ukládání TstringList.SaveToFile z vedlejšího vlákna. Zkoušel jsem přesně toto ukládání obalit kritickou sekcí, ale nepomohlo.
Uložení z hlavního vlákna proběhne v pořádku, ale ten samý TstringList se uloží prázdný(to co naplnilo vedlejší vlákno tam není)
Takova kontrolni otazka: tu (jednu, spolecnou) kritickou sekci jsi dal ke kazdemu zapisu v aplikaci? Zadnou chybu to nikde nehlasi?

Lepsi reseni je otevrit se ten soubor jako stream v exclusive modu a misto SaveToFile pouzit SaveToStream. A po kazde I/O operaci zkontrolovat vysledek, a pro ACCESS_DENNIED pres nejaky retry mechanismus po nejake dobe operaci zopakovat.
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: Mi.Chal. 15-05-2013, 20:11:08
Jestli to chápu dobře, tak jeden StringList plníš z více vláken? Je StringList thread-safe (mělo by to být napsané v dokumentaci, podle diskuzí typu http://objectmix.com/delphi/633638-do-tstringlist-add-tstringlist-delete-methods-threadsafe.html není), případně přístup k němu synchronizován?
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: Hdm 16-05-2013, 08:19:37
TStringList je property objektu, který se vytvoří v hlavním vlákně hned při startu programu.
Po té je plněn, ale pouze z toho vedlejšího vlákna.
Nakonec informace z objektu zobrazuje hlavní vlákno.

Žádnou chybu program nehází a hlavní vlákno vidí TStringList prázdný.

Nyní se snažím dokrokovat kam až program doběhne(, ale jde to pomalu - když krokuju z Delphi více vláken tak se po několika krocích sekne celé Delphi a musím ho restartnout :-(   )

Teď mě napadlo, že zkusím ve vedlejším vláknu vytvořit nějaký dočasný SL a ten na ThreadEnd pak předhodit SL v objektu.

Doplním další informace co jsem obdržel od tech. podpory a co jsem sám vyzkoumal:

Problém je pouze na Win7 aWin8. Nezáleží na home, profi... 32/64bit

Další anomálie jsem zjistil i v jiných částech kódu, které se vláken netýkají, takže tady už fakt začínám být dost tápající.
Poměr u zákazníků nefunkčních Win7/8 proti funkčním je momentálně asi 1:15.

Jeden příklad z mého zoufalství:
Mám sadu HW identických notebooků, kde:

Takže zatím jsem vyloučil problém na HW.

Dále zkoumám zda na to nemůžou mít vliv nějaké drivery či nastavení OS.
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: Mi.Chal. 16-05-2013, 10:54:29
TStringList je property objektu, který se vytvoří v hlavním vlákně hned při startu programu.
Po té je plněn, ale pouze z toho vedlejšího vlákna.
Nakonec informace z objektu zobrazuje hlavní vlákno.

Žádnou chybu program nehází a hlavní vlákno vidí TStringList prázdný.

No a to je blbě, prostě stringlist není (předpokládám) thread safe, takže k němu nemůžeš přistupovat z víc vláken, aniž bys to synchronizoval. Při přidávání nových záznamů se reorganizuje pole, které to interně používá, takže klidně ti může vracet nevalidní hodnoty nebo prázdný seznam, záleží jenom na tom, kdy se to sejde. Tohle jsou věci, které je potřeba dobře napsat v kódu, pokud to máš blbě, tak to může někdy fungovat a někdy ne. Což je nejspíš to, co se ti děje. Třeba dictionary v .Net se chová tak, že vrací klíče s null hodnotou, které do ní ale dát nejdou. Nebo při konkurentním přístupu dojde k zamrznutí těch dvou zúčastněných threadů, takže ti celá aplikace vytuhne.
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: pf1957 16-05-2013, 10:58:31
Nyní se snažím dokrokovat kam až program doběhne(, ale jde to pomalu - když krokuju z Delphi více vláken tak se po několika krocích sekne celé Delphi a musím ho restartnout :-(   )

Nekrokuj to, ale zuzuj si postupne prostor pomoci breakpointu. A jestli se jedna o nejaky race condition bug, tak ho stejne s velkou pravdepodobnosti v debuggeru nechytis a budes muset pouzit logovani.

Citace
Teď mě napadlo, že zkusím ve vedlejším vláknu vytvořit nějaký dočasný SL a ten na ThreadEnd pak předhodit SL v objektu.

Jedna z prvnich veci, ke ktere by ses mel dobrat, zda je to problem obsahu nebo I/O operace: takze si v miste, kde to zapisujes do souboru, vytvor lokalni pomocny SL, napln ho nejakym Lorem Ipsum generatorem, zapis ho do souboru a zase SL zrus. Tim bys mel vyloucit interakci s ostatnimi thready a pri trochu systematickem pristupu by nemel byt zadny problem zjistit, proc ti ev. Save selhava.


Citace
  • Win7 64bit předinstalované > program nechodí správně

Kdyz vidim tohle, tak si vzpomenu na zakernou, ale mnohokrat ruzne zminovanou zalezitost, ze se predinstalovana wokna (ja mam zkusenost s Win7) tvari jako spravne cesky nainstalovana, ale nekde maji uvnitr neco spatne nastaveno kolem NLS, takze zejmena aplikace, ktere nejsou vyvinute v unicode ale ANSI, mivaji problemy. Takze prvni co bych udelal na kazdych ceskych preidinstalovanych windows: nastavil bych EN, restartoval, nastavil CZ a restartoval.
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: pf1957 16-05-2013, 11:06:56
No a to je blbě, prostě stringlist není (předpokládám) thread safe, takže k němu nemůžeš přistupovat z víc vláken, aniž bys to synchronizoval.
TStringList neni thread safe. Ale jestli (?) je to jak pise, ze po tom stringu saha vzdycky jenom z jednoho mista a nikdy ne soucasne z vice, tak by mu to nemelo vadit.
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: Mi.Chal. 16-05-2013, 11:31:19
TStringList neni thread safe. Ale jestli (?) je to jak pise, ze po tom stringu saha vzdycky jenom z jednoho mista a nikdy ne soucasne z vice, tak by mu to nemelo vadit.

píše, že vlákno plní v jednom vlákně a v UI threadu se mu tváří prázdný, to je přístup z dvou threadů. Jinak nějakou sychronizaci asi má, viz to EnterCriticalSection(tmpLock);. Otázka ale je, jestli to má všude, kde s tím stringlistem pracuje (čtení i zápis).
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: pf1957 16-05-2013, 11:41:43
píše, že vlákno plní v jednom vlákně a v UI threadu se mu tváří prázdný, to je přístup z dvou threadů. Jinak nějakou sychronizaci asi má, viz to EnterCriticalSection(tmpLock);. Otázka ale je, jestli to má všude, kde s tím stringlistem pracuje (čtení i zápis).
Ne ze bych se chtel prit o necem, o cem vim kulovy, ale ja textu:
Citace
TStringList je property objektu, který se vytvoří v hlavním vlákně hned při startu programu.
Po té je plněn, ale pouze z toho vedlejšího vlákna.
Nakonec informace z objektu zobrazuje hlavní vlákno.
rozumim tak, ze ty operace probihaji po sobe: v main threadu vytvori instanci SL, pak spusti thread, ten do te instance pise (a asi dela i to SaveToFile?) a kdyz thread skonci (o par radku niz pise neco o ThreadEnd), tak obsah SL zobrazi v hlavnim threadu. Takze me z toho zadna paralelni operace se SL nevyplyva (i kdyz sam bych to udelal poradne a thread safe).
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: Hdm 16-05-2013, 13:13:35
je to jak píše pf1957. Je to samozřejmě bezpečně odděleno přes kritické sekce a dost jsem nad tím strávil, takže tam problém nevidím. K SL se přistupuje postupně, nikdy najednou ve více vláknech.

Každopádně jsem pokročil díky informaci o přepnutí lokálního nastavení CZ>EN>CZ co mi radí pf1957. Už jsem na to v minulosti narazil a dělal jsem kód s ochranou, že toto může nastat, ale ouha je to ještě zákeřnější než jsem si myslel.

Pokud celý nastavení locale přepnu na EN(spojené státy) tak program jede OK.
Pokud to přepnu zpět na CZ (CZ>EN>CZ) tak to nejede.

Zkusil jsem dát EN formát datumu v českém prostředí a zjistil problém ve standartních Delphi funkcích Now a StrToDateTime

Kód: [Vybrat]
var
tmpDT : TDateTime;
tmpString : String;


tmpString := DateTimeToStr(Now);
// vrací např. 16. 5. 2013 12:50:01   (povšimněte si mezer za tečkami v datu)

tmpDT :=  StrToDateTime(tmpString);
// spadne do výjimky, že není validní datum ve stringu

tmpDT :=  StrToDateTime('16.5.2013 12:50:01');
// po odstranění mezer za tečkami je situace stejná, také chyba

tmpDT :=  StrToDateTime('16/5/2013 12:50:01');
// proběhne v pořádku
Celkově z toho vyplývá, že funkce Now pracuje v českém tvaru, ale funkce StrToDateTime očekává tvar EN.

Nyní se pokouším zjistit jak OS donutit, aby se celý nastavil na CZ. Pokouším se manipulovat hodnotami v registrech:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Language]
"InstallLanguage"="0409"
"Default"="0405"
Ale zatím se zdá, že OS na změnu nereaguje.


Takže celá záležitost s vlákny a SL je mimo hru, protože ve vláknu je i převod datumu na kterém to spadlo do ošetřené výjimky, nehlásilo na venek chybu a vracelo default hodnotu. Dále to pak nemělo podle datumových podmínek žádná data k naplnění SL proto byl SL nakonec prázdný. Toto mě zmátlo a špatně navedlo na problém ve vláknech.


EDIT:Oprava drobnosti v kodu
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: Mi.Chal. 16-05-2013, 15:04:29
Now nepracuje v žádném tvaru, to vrací číslo odpovídající aktuálnímu datu a času, při zobrazování se naformátuje.

Nemůžeš prostě specifikovat formát data? Pokud na něm tak moc záleží a potřebuješ konkrétní formát, tak ho prostě specifikuj v těch konverzních funkcích jako parametr (alespoň doufám, že to šlo). Měnit kvůli tomu nastavení systému mi přijde jako lamerský přístup někoho, kdo ten formát neumí specifikovat nebo neví o tom, že to jde. Na nastavení systému bych se nespoléhal.
Název: Re:predinstalovany HP minitower - problem s ukladanim html souboru
Přispěvatel: Hdm 20-05-2013, 08:11:53
Mě nezáleží na formátu data, jak jsem psal  to i v EN tvaru. Na čem mě záleží je to, aby všechny funkce pracovaly se stejným tvarem. Pokud Now je číslo, pak je problém v StrToDateTime a DateTimeToStr, protože jedna funkce vrací jiný formát než druhá požaduje.

Řešit to budu, jak jsi také navrhl, úplným oddělením formátu od OS a celé to budu řešit na své straně.

Každopádně díky oběma za rady.