Динамично свързване
28 отговора
777 прегледа
Динамично свързване
Проблемът ми е свързан с многоплатформено приложение, което трябва да работи поне под Windows и Linux. Та значи, искам аз да имам външни за изпълнимата програма библиотеки, които при всяко нейно пускане да се свързват към нея и даработят като неразделна и неотличима от останалия код нейна част. По този начин ще мога а) като поправям грешки в библиотека да дам на клиентите само новата библиотека и по-важното - б) да не давам на клиентите функционалност, която не са си платили. Вместо нея ще им връча празни (stub) функции, които не вършат нищо, но са нужни, за да може linker-а да ми свърже програмата.
Кодът в библиотеката трябва да има read/write достъп до паметта на кода в "основната" част, както и да може да прави всякакви операции - заделяне на памет, която после основния код да може да освободи, освобождаване на памет, заделена от друг код, директно и пълно използване на handle на файл, сокети, ... всичко, за което се сети човек.
Дотук добре. Под Linux проблем нямам - правя си програмчето динамична библиотека (нещо-си.so), пускам си основния код и в този момент ld (динамичния линкер) има грижата да направи resolve на липсващите (външни) символи в основния код, да намери необходимите библиотеки, да ги зареди в паметта и да попълни конкретните стойности за тези символи. След тази процедура програмчето ми работи все едно е статично свързано и кодът в библиотеката на практика е неразличим от кода в ядрото.
В Windows, обаче, имаме проблем. Доколкото разбрах (аз програмист под Windows не съм, затова и питам по-знаещите от мен), единственият начин човек да си направи външни библиотеки, които да се свързват динамично при всяко пускане, е DLL. Хубаво, обаче кодът във въпросните DLL далеч не е равноправен с останалия код, особено когато говорим за управление на паметта. Тоест, трябва да взимам специални мерки, ако (да кажем) код в библиотеката задели памет, връчи я на основния код и си замине. В такъв случай кой ще освободи тази памет, след като си свърша работата с нея? Да я връщам на DLL-а за целта не ме блазни, а като че ли друг начин няма... Че не мога да викам функциите директно, а трябва да си поискам указател към тях, мога да го приема, не е голям проблем, ама това с паметта хич не ме радва.
Някой знае ли нещо повече по въпроса?
Кодът в библиотеката трябва да има read/write достъп до паметта на кода в "основната" част, както и да може да прави всякакви операции - заделяне на памет, която после основния код да може да освободи, освобождаване на памет, заделена от друг код, директно и пълно използване на handle на файл, сокети, ... всичко, за което се сети човек.
Дотук добре. Под Linux проблем нямам - правя си програмчето динамична библиотека (нещо-си.so), пускам си основния код и в този момент ld (динамичния линкер) има грижата да направи resolve на липсващите (външни) символи в основния код, да намери необходимите библиотеки, да ги зареди в паметта и да попълни конкретните стойности за тези символи. След тази процедура програмчето ми работи все едно е статично свързано и кодът в библиотеката на практика е неразличим от кода в ядрото.
В Windows, обаче, имаме проблем. Доколкото разбрах (аз програмист под Windows не съм, затова и питам по-знаещите от мен), единственият начин човек да си направи външни библиотеки, които да се свързват динамично при всяко пускане, е DLL. Хубаво, обаче кодът във въпросните DLL далеч не е равноправен с останалия код, особено когато говорим за управление на паметта. Тоест, трябва да взимам специални мерки, ако (да кажем) код в библиотеката задели памет, връчи я на основния код и си замине. В такъв случай кой ще освободи тази памет, след като си свърша работата с нея? Да я връщам на DLL-а за целта не ме блазни, а като че ли друг начин няма... Че не мога да викам функциите директно, а трябва да си поискам указател към тях, мога да го приема, не е голям проблем, ама това с паметта хич не ме радва.
Някой знае ли нещо повече по въпроса?
Re: Динамично свързване
функциите можеш да си ги викаш директно, но за целта при компилацията трябва да линкнеш .lib файла, който се генерира заедно с .dll-a, другото е по-гъвкаво.
за паметта има начин да се направи, въпреки, че не ти го препоръчвам.
най-добре е където паметта се заделя там и да се освобождава, ако непременно държиш да заделяш на едно място а да освобождаваш на друго трябва да гарантираш, че .dll-а и .exe-то използуват една и съща run time библиотека, това за VC++ се контролира със "use runtime library" в project settings c/c++.
това е много гадно ограничение и на практика значи, че ако смениш версията на компилатора например, ще трябва да прекомпилираш и .ехе и .длл.
отделно този .длл ще е почти неизползваем ако искаш да го използваш и от други приложения, така че по-добре се придържай към принципа, където заделяш памет, там я освобождавай.
Пламен
за паметта има начин да се направи, въпреки, че не ти го препоръчвам.
най-добре е където паметта се заделя там и да се освобождава, ако непременно държиш да заделяш на едно място а да освобождаваш на друго трябва да гарантираш, че .dll-а и .exe-то използуват една и съща run time библиотека, това за VC++ се контролира със "use runtime library" в project settings c/c++.
това е много гадно ограничение и на практика значи, че ако смениш версията на компилатора например, ще трябва да прекомпилираш и .ехе и .длл.
отделно този .длл ще е почти неизползваем ако искаш да го използваш и от други приложения, така че по-добре се придържай към принципа, където заделяш памет, там я освобождавай.
Пламен
Ама
ако си свържа функциите от .lib файла няма ли да получа статично свързване? Нали точно това се опитвам да избегна - искам библиотеките да се свързват при всяко пускане на програмата ми ... и точно това ми дава Linux-а. Въпросът ми е може ли същото да стане и под Windows?
Нямам проблем да използвам една и съща runtime библиотека, но това че кодът е един и същ, гарантира ли ми, че работи върху едни и същи данни? Щото, доколкото разбрах, DLL-а работи като отделен процес, който просто има read достъп до паметта ти; т.е. тя е map-ната в неговото адресно пространство, даже май на същия адрес. Добре, ама всеки процес си има собствен heap, от който заделя памет въпросната runtime библиотека, използвайки контекста на процеса, затова и не можеш от друг процес (основната програма) да освободиш памет на DLL-а. Или бъркам?
Хич не ми се ще библиотеката да си освобождава сама паметта, щото се нарушава логиката на програмата ми. Идеята е код в DLL-а да направи обект, който после да връчи на основния код; този обект е собственост на главната програма и е нейна отговорност като си свърши работата с него да го освободи. И някак си ми се струва тъпо да събудиш библиотеката и да й кажеш "на ти го този обект, а сега го изтрий". Така де, в краен случай това и ще направя: всеки клас ще си има нещо като:
virtual destroy () {
delete this;
}
Ама сещаш се, грозна картинка ...
Нямам проблем да използвам една и съща runtime библиотека, но това че кодът е един и същ, гарантира ли ми, че работи върху едни и същи данни? Щото, доколкото разбрах, DLL-а работи като отделен процес, който просто има read достъп до паметта ти; т.е. тя е map-ната в неговото адресно пространство, даже май на същия адрес. Добре, ама всеки процес си има собствен heap, от който заделя памет въпросната runtime библиотека, използвайки контекста на процеса, затова и не можеш от друг процес (основната програма) да освободиш памет на DLL-а. Или бъркам?
Хич не ми се ще библиотеката да си освобождава сама паметта, щото се нарушава логиката на програмата ми. Идеята е код в DLL-а да направи обект, който после да връчи на основния код; този обект е собственост на главната програма и е нейна отговорност като си свърши работата с него да го освободи. И някак си ми се струва тъпо да събудиш библиотеката и да й кажеш "на ти го този обект, а сега го изтрий". Така де, в краен случай това и ще направя: всеки клас ще си има нещо като:
virtual destroy () {
delete this;
}
Ама сещаш се, грозна картинка ...
Re: Динамично свързване
Ima nachin da zadeliash pamet i to takawa- neka ia narechem globalna pamet :). Opitaj se da widish help-a na functzii ot roda na GlobalAlloc. Oswen towa mogesh da izpolzwash za po-malki obemi danni i atomite na Windows-a.
Kato treti wariant mislia che ste ti swarshi rabota i file mapp-inga. Pri nego kato map-nesh opredelen file, no wmesto realen handle podadesh invalid_handle_value toj (bozata de :) ) se sesta da izpolzwa pametta (realno swap file-a- no towa ne mislia che ste ti e problem).
Wig help-a na CreateFileMapping i izpolzwaj warnatia handle kato parametar na functziata MapViewOfFile (i ne zabrawiaj UnmapViewOfFile).
Ima podrobni primeri na msdn.microsoft.com (tarsi napr. "global dll variables" i ste ti izleze prepratka kam edin takaw primer.
Kato treti wariant mislia che ste ti swarshi rabota i file mapp-inga. Pri nego kato map-nesh opredelen file, no wmesto realen handle podadesh invalid_handle_value toj (bozata de :) ) se sesta da izpolzwa pametta (realno swap file-a- no towa ne mislia che ste ti e problem).
Wig help-a na CreateFileMapping i izpolzwaj warnatia handle kato parametar na functziata MapViewOfFile (i ne zabrawiaj UnmapViewOfFile).
Ima podrobni primeri na msdn.microsoft.com (tarsi napr. "global dll variables" i ste ti izleze prepratka kam edin takaw primer.
Re: Ама
Chakaj, chakaj malko. Mislia che statichnoto swarzwane ne e tochno towa koeto si mislish. Kogato imash statichno swarzwane bibliotekata se zaregda PRI PUSKANE NA PROGRAMATA TI! Pri dinamichnoto ti ukazwash W KOJ MOMENT SLED KATO TI E PUSNATA PROGRAMATA da se zaredi bibliotekata! Podchertawam SLED!
Taka che .lib file-a ste ti swarshi rabota dotolkowa dokolkoto ne iskash primerno edna biblioteka da se load-wa sled kato user-a e natisnal button primerno!
Taka che .lib file-a ste ti swarshi rabota dotolkowa dokolkoto ne iskash primerno edna biblioteka da se load-wa sled kato user-a e natisnal button primerno!
Re: Ама
DLL-a ne raboti kato otdelen proces, osven tova se i zarejda v pametta na procesa koito go startira i ima sustite prava varhu neia kato osnovnia proces. V otdelen proces se startirat DLL-i koito realizirat ActiveX tehnologiata, no dokolkoto razbrah na teb ne ti triabva takuv.
Varianta s osvobojdavaneto na pamentta - mojesh da polzvash DLL_PROCESS_DETACH na DllMain i da razchistish vsichko koeto si zael ot nego. Ako pozlvash multithread pri puskaneto na vseki nov thread sled kato vednuj si zaredil DLL-a vlizash v DllMain s DLL_THREAD_ATTACH i saotvetno DLL_THREAD_DETACH pri prikliuchvaneto na threada.
Za LIB-a - toi e za implicit link na DLL-a, prosto ti spestiava LoadLibrary i getProcAddress v neusvest :> Probvai da linknesh s LIB-a koito ti pliue kompilatora zaedno s DLL-a i sled tva da razkarash DLL-a ot pytia .... garantirano ste izgarmi pri startirane na prilojenieto ;)
Ne znam kolko rabota ste ti svurshi tova .... ako moga da ti helpna s nesto poveche - pishi na maila :)
Varianta s osvobojdavaneto na pamentta - mojesh da polzvash DLL_PROCESS_DETACH na DllMain i da razchistish vsichko koeto si zael ot nego. Ako pozlvash multithread pri puskaneto na vseki nov thread sled kato vednuj si zaredil DLL-a vlizash v DllMain s DLL_THREAD_ATTACH i saotvetno DLL_THREAD_DETACH pri prikliuchvaneto na threada.
Za LIB-a - toi e za implicit link na DLL-a, prosto ti spestiava LoadLibrary i getProcAddress v neusvest :> Probvai da linknesh s LIB-a koito ti pliue kompilatora zaedno s DLL-a i sled tva da razkarash DLL-a ot pytia .... garantirano ste izgarmi pri startirane na prilojenieto ;)
Ne znam kolko rabota ste ti svurshi tova .... ako moga da ti helpna s nesto poveche - pishi na maila :)
Редактирано от Goose на
Бам!!
Сигурен ли си, че това е статично свързване? Според мен, когато свързваш статично обектни файлове (или библиотеки, ако щеш), се получава един изпълним файл, който съдържа целия код и не използва външни модули, за да работи. Хубавато е, че не зависиш от това, че някой може да ти сложи скапан DLL или да ти изтрие някой, или просто, че на системата на потребителя може и да няма необходимата ти библиотека. Лошото е, че ако решиш да направиш елементарен bugfix, трябва отново да направиш целия огромен изпълним файл и да го връчиш на потребителя.
Разбира се, може и да не съм прав. Няма да се учудя, ако Microsoft за пореден път са променили смисъла на понятията и статичното свързване е това, за което говориш.
Разбира се, може и да не съм прав. Няма да се учудя, ако Microsoft за пореден път са променили смисъла на понятията и статичното свързване е това, за което говориш.
Re: Бам!!
Tova ne e statichno svurzvane, ne burkai nestata :> Tva e implicit load na DLL-a :> Realno toa lib ne pravi nisto drugo .... i toia lib bez DLL-a ne mojesh da go izpolzvash. Za statichno svurzvane ste triabva da go kompilirash po savsem razlichen nachin ... ;) I ne ti triabva entry poin na DLL za tfa ;-P
Хм
А доколко са ефективни методите, за които говориш? Щото на мен ми трябва да заделям малки (около 200-300 байта) обекти и да ги използвам, общо взето, в реално време. Тоест, ако изведнъж някой реши да ми swap-не обекта на диска и ме замотае с няколко секунди, нещата вече ще са се прецакали.
Re: Бам!!
Tochno taka- statichno swarzwane, ili izrichno swarzwane e nachinat po kojto go prewegdat ot angl. Inache lib file ne e nisto poweche ot specifichen "header" na bibliotekata!
Re: Хм
Ami wig sega, misila che metoda e efectiven, pone dokolkoto moge da se gowori za efectivnost pod Windows :). Inache za realno wreme, ako naistina imash predwid "realno wreme" mogesh da zabrawish ako pishesh na application level (ring 3) na Windows. Mogesh da opitash da kombinirash vxd-ta (ring0) s applications, obache towa ste ti udari mnogo losho megduplatformenata sawmestimost! :(
А има ли начин
да заключиш паметта на процеса си и Windows да не се опитва да я swap-не?
Имам предвид точно реално време, макар че все пак имам грубо около 100 милисекунди да реагирам. Ако няма swap-ове и други екстри, на > 500 MHz машина това си е море от време...
Като говоря за ефективност, имам предвид и друго: обектите ми са сравнително малки, затова се чудя дали алокирането на 200 байта няма да изяде примерно 4k от глобалната памет, за която ми говориш?
Имам предвид точно реално време, макар че все пак имам грубо около 100 милисекунди да реагирам. Ако няма swap-ове и други екстри, на > 500 MHz машина това си е море от време...
Като говоря за ефективност, имам предвид и друго: обектите ми са сравнително малки, затова се чудя дали алокирането на 200 байта няма да изяде примерно 4k от глобалната памет, за която ми говориш?
Редактирано от Masklin на
Оххх
@#(*&*(#@ и преводачи, извинявайте за грубия език. Че не разбират много ми е ясно, ама да преведеш като статично свързване въпросния процес е пълна издънка. Както и да е, разбрахме се 
Добре де,
пак не разбрах: ако в DLL-а си алокирам памет, мога ли да я освободя в основното приложение с delete? Не ми върши работа DETACH, ако правилно го разбирам, защото искам библиотеката ми да продължи да си работи; в момента, в който съм свършил с обекта X и искам да го изтрия, като нищо мога да имам 100 нишки на библиотеката, които не са свършили и правят нови обекти. Не мога да си позволя да чакам всички да свършат, защото може да не стане никога или поне много дълго време - в продължение на часове. През това време паметта може да свърши. Отделно от това, в библиотеката може да има десетки класове, значи ако искам да освободя паметта, алокирана от нейни обекти, трябва да измисля някакъв доста сложен алгоритъм, за да разбера дали има жив такъв клас, или да ги накарам някак си да се регистрират при създаване и отрегистрират при умирането си. Въобще, става дявол на магаре за нещо толкова тривиално като delete...
Оппппп
Току-що прочетох още веднъж внимателно мнението на Goose. В крайна сметка, не са виновни само преводачите, ами и Microsoft. Един вид, правим си статично свързване за пред linker-а, което обаче е само шапка над DLL и доколкото разбирам, просто ти спестява използването на указатели, като използва функции, които ти викаш по име, а те вместо теб стигат до кода в библиотеката чрез указатели.
Тоест, хем имаш статично свързване, хем нямаш. Честно казано, не разбирам архитектите в Microsoft. Защо не са оставили възможност функцията да се вика по име и при зареждане на програмата да се свързва целия код? Нищо не губиш, а ако ти потрябва runtime да избираш кой DLL да зареждиш (което е рядкост) - искаш си указател към функцията и си я викаш през него...
Тоест, хем имаш статично свързване, хем нямаш. Честно казано, не разбирам архитектите в Microsoft. Защо не са оставили възможност функцията да се вика по име и при зареждане на програмата да се свързва целия код? Нищо не губиш, а ако ти потрябва runtime да избираш кой DLL да зареждиш (което е рядкост) - искаш си указател към функцията и си я викаш през него...
Re: Добре де,
Nikakav problem, dll-a si se startira v pametta na procesa, niama sobstvena takava :>
Не е така
направих прост опит - DLL, в който има една единствена функция, която прави new на указател към int, записва нещо в получената памет и дава този указател на викащия. Е, викащия може да чете и пише във въпросната памет, обаче при delete получаваме assertion failed...
Re: Динамично свързване
Predawaneto na pointeri mezhdu EXE i DLL-i e slozhna i neprijatna rabota, s kojato, basically, ne ti trjabwa da se zahwashtash (oswen ako ne si reshil, che imash prekaleno mnogo kosa).
Warianti:
- izpolzwaj COM;
- ne alokiraj pamet w DLL-ite
- prestrukturiraj si API-to taka, che da njama nuzhda ot towa prehwyrljane na zadeleni obekti - opitaj se da go naprawish kolkoto mozhe po-stateless.
Warianti:
- izpolzwaj COM;
- ne alokiraj pamet w DLL-ite
- prestrukturiraj si API-to taka, che da njama nuzhda ot towa prehwyrljane na zadeleni obekti - opitaj se da go naprawish kolkoto mozhe po-stateless.
Ами...
как да ти кажа... аз правя точно state машини 

COM не ми върши работа - прекалено тежко е, когато искаш да кажеш "стана еди-какво си" и другарчето оттатък трябва да реагира за < 100 ms ... и не си само ти, а още поне 1000 маймуни.
За алокирането на памет... бих могъл да се справя, ама ще ми е неудобно. Мога, например, да си направя някакъв пул с обекти, от който да си взимам при необходимост. Тоест, на практика да емулирам new/delete. Макар че си има предимства...
Хареса ми това за косата
COM не ми върши работа - прекалено тежко е, когато искаш да кажеш "стана еди-какво си" и другарчето оттатък трябва да реагира за < 100 ms ... и не си само ти, а още поне 1000 маймуни.
За алокирането на памет... бих могъл да се справя, ама ще ми е неудобно. Мога, например, да си направя някакъв пул с обекти, от който да си взимам при необходимост. Тоест, на практика да емулирам new/delete. Макар че си има предимства...
Хареса ми това за косата