C++ Builder 2009 - rtl, dll i synchronizacja wątków

0

Witam, dużo korzystam z tego forum od kilku lat, dziś zamieszczam swój pierwszy post, ponieważ tym razem nie mogę znaleźć nigdzie odpowiedzi na mój problem.
Przed długi czas budując aplikacje (exe i dll) używałem opcji 'dynamic rtl' i 'build with runtime packages', ale ostatnio chciałem je wyłączyć, żeby nie musieć dostarczać bpl'i w instalatorach.
Tutaj zaczął się problem, który napotkałem w swojej sporej aplikacji, ale udaje mi się zreprodukować w bardzo prostym zestawie exe i dll.

Mam aplikację exe.exe która jest po prostu formą z guzikiem, który wywołuje na głównym wątku funkcję z pliku dll.dll. Funkcja w dll'u startuje nowy wątek, który w pewnym momencie próbuje się zsynchronizować z głównym wątkiem. Jeśli mam w obu projekatach (exe i dll) zaznaczone opcje 'dynamic rtl' i 'build with runtime packages' rtl, wszystko działa jak należy. Jeśli w którymkolwiek z projektów którakolwiek opcja jest odznaczona, mój nowy wątek nie może się zsynchronizować z głównym. Dodam, że jeśli funkcję z dll'a przeniosę do exe, to niezależnie czy dynamic rtl jest zaznaczone czy nie, wszystko działa ok.
Czy mógłby mi ktoś wytłumaczyć dlaczego?
Przede wszystkim nie rozumiem jaka jest różnica między opcją 'dynamic rtl' a 'build with runtime packages' za wyjątkiem tego że przy tej drugiej wyszczególniam których bibliotek nie chcę wkompilowywać w mój projekt.
Po drugie do tej pory myślałem, że jedyna różnica polega na tym, że albo biblioteki będą wkompilowane, albo będą musiały być dostarczone osobno, ale że nie ma to wpływu na działanie aplikacji, a w moim przypadku okazuje się, że ma.
Po trzecie chciałbym poznać jakąś regułę które powie mi kiedy muszę, a kiedy nie mogę korzystać z jednej bądź drugiej formy dołączania bibliotek.

Jeśli opis mojego problemu jest nie jasny chętnie służę przykładem grupy projektowej gdzie można zobaczyć co zrobiłem i co nie działa. Z góry dziękuję za pomoc.

0

Wystaw mi 3 paczki - 1 źródła, 2 skompilowaną działającą, 3 skompilowaną niedziałającą (z całym zestawem potrzebnych BPLi), z ciekawości zajrzę do środka.

0

Załączam paczki. W niedziałającej wersji nie ma bpl'a, ponieważ tam mam odznaczone opcje 'build with runtime packages' i 'dynamic rtl' (co widać w załączonych źródłach). Jak pisałem w pierwszym poście, jeśli tylko zaznaczę obie opcje w obu projektach (dll i exe), i na liście runtime packages znajdzie się 'rtl' to mamy działającą wersję. Sam program ma 2 guziki - 1 startuje wątek z poziomy exe, a drugi startuje taki sam wątek z poziomu dll. W manadżerze zadań można zaobserwować w niedziałającej wersji że liczba używanych wątków wzrasta po każdym naciśnięciu drugiego guzika. Z góry dzięki za wyjaśnienie zjawiska.

1

Problem tkwi w Synchronize(), wrzuciłem do debuggera i kod wisi na WaitForSingleObject() dla eventu utworzonego wewnątrz Synchronize(), szybkie wyszukanie i problem dokładnie wyjaśniony na SO:

http://stackoverflow.com/questions/3772196/synchronize-hangs-up-the-thread

Czyli mówiąc krótko jeśli używasz BPL-i to jest 1 lista synchronizacyjna, jak używasz EXE i DLL własnej produkcji, to i EXE i DLL ma swoją listę synchronizacji, które powodują blokowanie się wątku po wywołaniu Synchronize().

Problem ten opisany jest również na:

http://qc.embarcadero.com/wc/qcmain.aspx?d=22267

0

Dziękuję za odpowiedź, uświadamiam sobie, że wiem mniej niż myślałem...
Szukam w kodzie (classes.pas) gdzie jest zadeklarowana zmienna SyncList ale nie mogę się doszukać, help też milczy w temacie. Rozumiem, że SyncList to swojego rodzaju zmienna globalna, która jeśli linkuje rtl.bpl dynamicznie jest współdzielona pomiędzy exe i dll za pośrednictwem rtl.bpl, a w przeciwnym razie exe i dll mają swoje oddzielne instancje tej listy.
Czyli generalizując jeśli używam w dll'u, bezpośrednio lub pośrednio, jakiś zmiennych globalnych bpl'a i zamierzam z tych samych zmiennych korzystać w exe to muszę linkować tego bpl'a dynamicznie. Mam rację?
Problem w tym, że trzeba być świadomym faktu, że exe i dll zamierzają współdzielić jakiś zasób.
Czy jest jakaś złota metoda na posiądnięcie tej wiedzy? Nie ma nigdzie wzmianki o tym w opisie klasy TThread czy metory Synchronize (przynajmniej nie znajduję), a wg mnie nie jest to też wcale intuicyjne, czyli pozostaje przy dodaniu każdej nowej funkcjonalności sprawdzać czy działa a jak nie to rozgrzebywać pliki pas i zastanawiać się którego bpl'a dodać?

Uparłem się żeby nie linkować bpl'i dynamicznie, ponieważ mam aplikacje exe korzystające czasem z 5 plików dll. Niektóre te pliki są mi dostarczane z zewnątrz i korzystają np. z indy. Jeśli teraz twórca 1 dlla ma inną wersję indy niż ja (ta sama wersja codegear'a), to mamy problem, bo indycore120.bpl mogę dostarczyć tylko 1, więc pytanie który, ten którego potrzebuje ten 1 dll, czy ten którego potrzebuje reszta. Wspominam o tym, bo być może prościej jest rozwiązać ten problem, niż ten z wykrywaniem który bpl trzeba linkować dynamicznie, a którego nie trzeba. Poza tym nadal możemy dojść do momentu kiedy mój dostawca dll'a chce synchronizować wątek i potrzebuje rtl.bpl przy czym on używa lekko nowszej wersji Embarcadero.

0

wyłączenie 'dynamic rtl' powoduje, że ważne standardowej biblioteki staną się częścią twojej dll-ki.
Oznacza to, że taka dll-ka będzie miała własnego heapa i własne singletony standardowej biblioteki.
Tak się dzieje np z kolejką metod do synchronizacji (tak jak to jest opisane w wątkach stackoverflow).
Użycie 'dynamic rtl' powoduje, że kod i obiekty ze standardowej biblioteki są współdzielone przez wszystkie elementy kodu (exe, dll, bpl).

Wyłączenie tej opcji jest przydatne, jeśli trzeba wykorzystać dll-kę w programie nie opartym o VCL.

1 użytkowników online, w tym zalogowanych: 0, gości: 1