Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: biggles001 19. 04. 2011, 17:20:37

Název: Spuštění jiného programu z C
Přispěvatel: 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?
Název: Re: Spuštění programu
Přispěvatel: martin 19. 04. 2011, 17:43:46
fork(2) + exec(3) příp. execve(2)

Na win existují ekvivalenty
Název: Re: Spuštění jiného programu z C
Přispěvatel: biggles001 20. 04. 2011, 06:28:01
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í.
Název: Re: Spuštění jiného programu z C
Přispěvatel: martin 20. 04. 2011, 08:13:25
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.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Ondřej Novák 20. 04. 2011, 09:55:15
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.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Logik 20. 04. 2011, 15:49:53
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.
Název: Re: Spuštění jiného programu z C
Přispěvatel: martin 20. 04. 2011, 16:33:38
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.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Logik 20. 04. 2011, 17:16:12
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ě?
Název: Re: Spuštění jiného programu z C
Přispěvatel: martin 20. 04. 2011, 17:26:13
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.
Název: Re: Spuštění jiného programu z C
Přispěvatel: eMko 20. 04. 2011, 17:42:37
A není lepší tu "výkonovou" část udělat jako knihovnu? Pak není třeba se štvát s nějakým execem.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Logik 20. 04. 2011, 17:46:19
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ů.
Název: Re: Spuštění jiného programu z C
Přispěvatel: martin 20. 04. 2011, 18:11:19
Jak s binárky udělám knihovnu?
Název: Re: Spuštění jiného programu z C
Přispěvatel: Logik 20. 04. 2011, 19:12:02
Jednoduše, funkcím, který chceš volat zvenku dáš modifikátor
Kód: [Vybrat]
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...
Název: Re: Spuštění jiného programu z C
Přispěvatel: martin 20. 04. 2011, 19:53:13
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.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Logik 20. 04. 2011, 21:56:16
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).
Název: Re: Spuštění jiného programu z C
Přispěvatel: biggles001 21. 04. 2011, 08:22:30
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ě.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Ondřej Novák 21. 04. 2011, 09:20:58
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.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Logik 21. 04. 2011, 09:40:07
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.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Ondřej Novák 21. 04. 2011, 11:46:46
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í :-)
Název: Re: Spuštění jiného programu z C
Přispěvatel: Logik 21. 04. 2011, 14:30:57
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.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Ondřej Novák 21. 04. 2011, 16:16:06
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
Název: Re: Spuštění jiného programu z C
Přispěvatel: Logik 21. 04. 2011, 17:27:49
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.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Ondřej Novák 22. 04. 2011, 15:57:21
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ě.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Sten 22. 04. 2011, 16:34:18
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.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Michal 23. 04. 2011, 09:49:36
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.
Název: Re: Spuštění jiného programu z C
Přispěvatel: Ondřej Novák 23. 04. 2011, 20:06:00
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.