Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: biggles001 19. 04. 2011, 17:20:37
-
Zdravím, mám menší problém s klasickým C:
Mám 2 programy - grafické rozhraní a výkonnou část, z grafické části potřebuji spustit výkonnou část tak, aby grafické rozhraní nebylo pozastaveno (funkce system), nebo zrušeno (exec*). Nic pořádného jsem nevygooglil. Jedniná fce, kterou sem našel ,a která volající program neukončí je popen na vytvoření roury, ale kůli tomu, že programy mají být multiplatformní ji nemůžu použít (pod wokna ju nedostanu).
Proto se táži Vás, nevíte o něčem, co by šlo použít?
-
fork(2) + exec(3) příp. execve(2)
Na win existují ekvivalenty
-
Napadlo mě ještě jiné řešení - vytvořil jsem si vlákno a tam to spustil funkcí system. Vypadá to, že tohle řešení je ideální.
-
Napadlo mě ještě jiné řešení - vytvořil jsem si vlákno a tam to spustil funkcí system. Vypadá to, že tohle řešení je ideální.
To má k ideálnímu řešení hodně daleko.
-
V linuxu fork a ve vytvorenem diteti exec. Tam kde funguje vfork tak pouzit ten, protoze fork muze selhat pokud aplikace ma zaalokovano vic nez polovinu volne pameti * povoleny overcommit.
Ve windows CreateProcess a nezapomenout pozavirat vsechna vytvorena HANDLE.
Pokud chcete sledovat zda proces bezi, pak v linuxu nejaka varianta funkce wait(), ve Windows funkce WaitForSingleObject pro jeden z vytvorenych HANDLE, ktere si samozrejme zavrete az po tom, co proces skonci.
-
No, vzhledem k tomu, že to řeší spousta lidí, tak bych neřešil kolo, ale použil některou z "osvědčených knihoven".
http://stackoverflow.com/questions/3019081/portable-c-library-for-ipc-processes-and-shared-memory-boost-vs-ace-vs-poco
Druhá možnost, co mě napadá, tak se vykašlat na spouštění procesů, výkonnou část zkompilovat jako commandline exáč + knihovnu a fce tý knihovny spouštět místo v spešl procesu jen v threadu.
Psaní vlastního multiplatformního exec bych viděl jako poslední možnost, protože to bude nejméně portabilní možnost, zatímco s již hotovou knihovnou vím, že to bue běhat všude.
-
No, vzhledem k tomu, že to řeší spousta lidí, tak bych neřešil kolo, ale použil některou z "osvědčených knihoven".
http://stackoverflow.com/questions/3019081/portable-c-library-for-ipc-processes-and-shared-memory-boost-vs-ace-vs-poco
Druhá možnost, co mě napadá, tak se vykašlat na spouštění procesů, výkonnou část zkompilovat jako commandline exáč + knihovnu a fce tý knihovny spouštět místo v spešl procesu jen v threadu.
Psaní vlastního multiplatformního exec bych viděl jako poslední možnost, protože to bude nejméně portabilní možnost, zatímco s již hotovou knihovnou vím, že to bue běhat všude.
Mně tedy přijde dost zvrhlé zanášet aplikaci knihovnou(ama) a tudíž závislostma (neřku-li jejíma chybama), když jde zrovna tohle nahradit jedním if-em.
-
O jakejch knihovnách mluvíš? Jestli o knihovnách zdrojovýho kódu, tak tam prostě přibalíš ke zdrojákům jejich současnou implementaci a máš to. Takovýdle jednoduchý fce tam jsou 100pro bez bugů. Navíc máš zajištěno, že pokud se v rozhraní OS něco změní, tak na to knihovna bude reagovat - nebudeš muset studovat, co se změnilo, prostě vezmeš novou verzi knihovny. A máš implementaci pro daleko větší škálu systémů. Jak ukazuje Ondra, on to ani pro Win/Lin není jen jeden if.
Kompilovat to můžeš staticky, takže žádné řešení závislostí nehrozí.
Nebo myslíš udělat to za pomocí dynamické knihovny? Není jedno, jestli to závisí na exáči, nebo na knihovně?
-
Bavíme se o spouštění binárky na pozadí. Mám asi malou fantazii, ale opravdu mě nenapadá, proč by se měla funkce fork(2), execve(2) a CreateProcess v jiné verzi OS měnit. Desítky let je to stejné.
A pokud není programátor schopen tahle 3 volání zkombinovat do jednoho ifdefu, tak by měl spíš použít nějaký python, ruby, tcl/tk apod. a obloukem se Cčku vyhnout.
-
A není lepší tu "výkonovou" část udělat jako knihovnu? Pak není třeba se štvát s nějakým execem.
-
Jo, to jsem taky navrhoval a přijde mi to jako nejlepší řešení. Akorát furt zůstavá problém v podobě multiplatformního vytváření threadů - to je ale jednodušší a na to existuje spousta jednoúčelovejch hotovejch kódů.
-
Jak s binárky udělám knihovnu?
-
Jednoduše, funkcím, který chceš volat zvenku dáš modifikátor
extern "C"
a přeložíš to s přepínačema
-shared -fPIC
(gcc, u jinejch překladačů to najdeš v dokumentaci)
Funkce pak spouštíš buďto dynamickym nahrátím knihovny (složitější), nebo knihovnu normálně přilinkuješ a napíšeš k ní hlavičkový soubory...
-
Jednoduše, funkcím, který chceš volat zvenku dáš modifikátor
jaké funkce u binárky? jaké překládání? biggles001 psal, že pouští výkonnou část přes system(3) tj. má binárku. Nepsal, že má zdrojový kód. Dotaz, myslím, zněl jasně. Kdyby měl zdrojové kódy, tak mě nenapadá (za daných okolností) proč by to takto rozděloval na 2 části. IMO je to typický případ, kdy má někdo binární "výkonnou" část pro 2 platformy bez dostupnosti zdrojáků a dělá si k nim GUI.
-
martin: Co kdybys nechal mluvit samotného tazatele? Ono zaprve mít takto oddělené binárky a gui frontend v samostatných exáčích je na linuxu vcelku běžný postup, takže bych se nedivil, ani kdyby ta binárka byla také jeho práce - a za druhé pokud to je multiplatformní aplikace, tak zpravidla bývá se zdrojovými kódy.
btw. Co se týče toho měnění, tak jak vidíš, standard se mění. Např ono vfork, které bylo do standardu přidáno relativně nedávno. Backward compatibility sice v drtivé většině zachovávaná je, ale "novější" řešení je většinou z nějakých důvodů lepší (viz např. fork/vfork).
-
Ty programy jsou moje práce - zdrojáky mám.
Jedná se o to, že ta výkonná část musí být samotnej spustitelnej program, protože se musí dát spustit třeba cronem,.. To gui je jen klikátko, kde si člověk může nastavit, co se bude dít a program spustit rovnou.
Neprogramuji moc dlouho, tak mívám někdy problémy. Díval jsem se na ten fork, podle toho co jsem četl, zduplikuje aktuální proces, což podle toho, co si myslím vytvoří identickou kopii procesu, který zabere stejné místo v paměti jako původní, sice jen na chvíli, než to zruším execvem, ale příjde mi to jako plýtvání systémovými zdroji. Pokud se pletu, opravte mě.
-
Fork nevytvari kopii, ale proces nasdili a kopie vznika az za behu, tak jak se meni obsah pameti v kazdem z obou procesu, rika se tomu copy on write a je to jedna ze zakladnich sluzeb strankovani za podpory procesoru. I tak je pravdou, ze se tam nejakymi prostredky plytva zbytecne, ale neni to tak hrozny, jak to na prvni pohled vypada. Proto vznikl vfork (virtual fork), ten funguje podobne ale u neho se predpoklada, ze vzdycky skonci execem. Vznikly child zastavi parenta, docasne prevezme vsechny prostredky parenta aby mohl provest treba nastaveni rour, signalu, zavreni ci otevreni deskriptoru, no a po zavolani exec se parent ze uvolni s tim, ze pokracuje tam kde prestal. vfork je rychlejsi, ale neni to skutecny fork, jen takovy fake.
Mimochodem, Windows nema tento mechanismus a ruzne akce provadene mezi (v)forkem a execem se tam musi resit jinak, treba sdilenim handlu (descriptoru) a s tim spojene problemy typu "kdo nese zodpovednost za uzavreni handlu". Paradoxne ve Windows se kvuli procesu vyplati poustet vlakno, ktery proces sleduje a po jeho skonceni uzavre vsechna sdilena handle. Atd.
-
biggles: no vždyť ta výkonná část může taky používat tu samou knihovnu, ne? Prostě udělej jednoduchou knihovnu a k ní dva fronendy pro cli a gui.
jinak to, co vfork kopíruje je tabulka stránek, u kterejch nastaví příznaky copy on write. Nic moc hroznýho to neni, používalo se to běžně u různejch multiprocesovejch serverů. Ale pokud je k dispozici vfork, není důvod ho nepoužít (pokud teda půjdeš tímto směrem).
ondra: jo, jo - linuxovej přístup vypadá na první pohled "hrozně nebezpečně", ale programuje se daleko líp. Windowsí create process je "allinone" bast.
-
ondra: jo, jo - linuxovej přístup vypadá na první pohled "hrozně nebezpečně", ale programuje se daleko líp. Windowsí create process je "allinone" bast.
On Microsoft nikdy nechtěl moc forkovat, Windowsy to dodnes neumí, větší tíha byla na vlákna. Možná se tím zase nějaké věci zjednodušují :-)
-
Jo, linux zas poměrně dlouho preferoval procesy oproti vláknům, to je fakt - a taky bych řek že vlákna jsou ve výsledku použitelnější (i když teď se zas vývojáři často vracej k samostatným procesům z důvodu bezpečnosti).
Rozdil ale je, že do linuxu se ty vlákna nakonec dostali a časem je i vyladili do rozumný výkonnosti. Zatimco create process je furt stejnej.
-
Holt si microsoft mysli, ze jen jeho zpusob je jediny spravny. Ono se to pozna snadno podle toho, kdo od koho kopiruje. Linux se postupne naucil vlakna, zatimco Windowse nikdo nenaucil forkovat (PS: cygwin to nejak emuluje, a ve WIndows 7 existuje nejake linuxove api, ktere to snad zvladne)
Jinak CreateProcess je userspacova zalezitost, kde je par kernel volani typu "zaloz prazdny proces", "Namapuj pamet noveho procesu do aktualniho" po kterem nasleduje natazeni image do pameti, relokace, natazeni DLL knihoven a konci to zase kernelovskym vytvorenim vlakna v procesu. Jenze jsem nevidel funkcni API kde by se daly tyto kroky volat separatne. Navic se to od verze meni
-
No, ono POSIX api bylo (volitelně) už v NT tuším 3.51 (nebo 4, teď nevím) - jenže když se MS cejtil dost silnej v kramflecích, tak ho zas vyřadil. Takže nějak to we winech jít musí, jen to nebude dokumentovaný.
Ale to co píšeš bych bezezbytku podepsal.
-
No zrovna teď řeším podobný task. Moje knihovna je založená na posílání různých notifikací při nastalé události. Umím podchytit události typu odemčení semaforu, otevření gate, uvolnění zámku, vykonání operace v jiném vláknu, dokonce i příchod dat na otevření socket. Zatoužil jsem po podobném rozhraní u ukončování procesů. Je tu několik zádrhelů.
Proces spustím normálně vfork + execve ovšem v libovolném vlákně, kde to potřebuji. V tom samém vlákně mohu udělat maximálně waitpid (na rozhraní vyvedeno jako join(), aby to bylo podobné jako u threadů). Thready umí mimojiné při ukončení obeslat listenery a na nich zavolat metodu wakeUp. U Procesu to bude horší, nicméně napadlo mě na to vyčlenit vlákno. Nechce se mi ale vyčlenit vlákno per process, ani se mi nechce vytvářet vlákno v případě, že to není potřeba (volající nebude registrovat listenery). Napadlo mě to udělat tak, jak to mám u soketů, že si soket zaregistruju na globální kolektor, který spustí vlákno a ve vlákně provádí select. Jenže u procesů to není tak jednoduché. Jednak mě docela děsí to, že nemohu selektivně čekat na děti. Mohu čekat jen na všechny, nebo na jedno. Další problém je, že na děti budu čekat v jiném vlákně, než vznikly. A třetí zádrhel je, co udělá linux, když čekatelů na děti bude náhodou víc, třeba když jeden bude čekat na všechny děti a druhý bude čekat jen na jedno selektivně.
-
Na takové věci doporučuji eventfd. Je to asi nejlepší řešení, jak vytvořit něco, na co se dá snadno čekat (selectem). Potom stačí v signal handleru SIGCHLD do příslušného eventfd zapsat.
-
Osobně bych zkusil doporučení z příspěvku výše:
* dynamickou knihovnu s výkonným kódem
* separátní EXE pro jednotlivá prostředí volající tuto knihovnu
Pokud je problém se zdroji, je vždy možné zkusit něco sdílet. Za to zaplatíš řízením přístupu, ale celkově to není hrozné.
Osobně se mi zdá, že tohle je mnohem jednodušší způsob než roury nebo meziprocesová komunikace...
Hodně štěstí
M.
-
Taková kaciířská myšlenka. Lze v handleru SIGCHLD zavolat waitpid z WNOHANG? To abych se rovnou dozvěděl, které dítě umřelo.