Vytváření nových procesů v jazyce C: Porovnání verzí
(Rozšíření) |
m (+kat) |
||
(Není zobrazena jedna mezilehlá verze od stejného uživatele.) | |||
Řádka 3: | Řádka 3: | ||
V následujícím příkladu je použita funkce <CODE>execl()</CODE>, která vyžaduje, aby spouštěný program byl zadán s plnou cestou a je možné předávat přepínače a parametry jako na příkazovém řádku v shellu. | V následujícím příkladu je použita funkce <CODE>execl()</CODE>, která vyžaduje, aby spouštěný program byl zadán s plnou cestou a je možné předávat přepínače a parametry jako na příkazovém řádku v shellu. | ||
− | + | <source lang="C"> | |
− | + | #include <stdio.h> | |
− | + | #include <unistd.h> | |
− | + | int main () | |
− | + | { | |
− | + | int ret; | |
− | + | printf("Start... execl /bin/ls\n"); | |
− | + | ret = execl ("/bin/ls", "ls", "-l", (char *)0); | |
− | + | printf("Chyba: navrat uz nebude\n"); | |
− | + | return 1; | |
+ | } | ||
+ | </source> | ||
Další příklad používá funkci <CODE>execle()</CODE>, která umožňuje nastavit proměnné prostředí. Nedojde tedy k dědění proměnných prostředí z rodiče, což může být užitečné v případech, kdy by mohlo dojít k nežádoucímu ovlivnění nově spuštěného programu. Na řádku 6 jsou připravené proměnné prostředí HOME a LOGNAME. Pomocí funkce ''execle'' se následně spustí příkaz <CODE>printenv</CODE>, který vypíše všechny proměnné prostředí. Po spuštění programu budou ve výpisu jen výše zmíněné 2 proměnné <CODE>HOME</CODE> a <CODE>LOGNAME</CODE>. Pokud byste zkusili stejný příkaz spustit v předchozím příkladu, bude vypsáno nepoměrně více proměnných prostředí, které jsou při použití ''execl'' zděděny od rodiče. | Další příklad používá funkci <CODE>execle()</CODE>, která umožňuje nastavit proměnné prostředí. Nedojde tedy k dědění proměnných prostředí z rodiče, což může být užitečné v případech, kdy by mohlo dojít k nežádoucímu ovlivnění nově spuštěného programu. Na řádku 6 jsou připravené proměnné prostředí HOME a LOGNAME. Pomocí funkce ''execle'' se následně spustí příkaz <CODE>printenv</CODE>, který vypíše všechny proměnné prostředí. Po spuštění programu budou ve výpisu jen výše zmíněné 2 proměnné <CODE>HOME</CODE> a <CODE>LOGNAME</CODE>. Pokud byste zkusili stejný příkaz spustit v předchozím příkladu, bude vypsáno nepoměrně více proměnných prostředí, které jsou při použití ''execl'' zděděny od rodiče. | ||
− | + | <source lang="C"> | |
− | + | #include <stdio.h> | |
− | + | #include <unistd.h> | |
− | + | int main () | |
− | + | { | |
− | + | int ret; | |
− | + | char *env[] = { "HOME=/usr/home", "LOGNAME=home", (char *)0 }; | |
− | + | printf("Start... exec /usr/bin/printenv\n"); | |
− | + | ret = execle ("/usr/bin/printenv", (char *)0, env); | |
− | + | printf("Chyba: navrat uz nebude\n"); | |
− | + | return 1; | |
+ | } | ||
+ | </source> | ||
Funkce ''fork'' slouží k vytvoření procesu potomka, který je identický s rodičem. Rozlišení mezi rodičem a potomkem je možné pomocí testování návratového kódu funkce ''fork''. Rodič získá po návratu funkce PID procesu potomka. Potomek získá jako návratový kód 0 (nulu), protože si může zjistit svoje PPID (Parent PID, tj. číslo procesu rodiče) pomocí funkce <CODE>getppid()</CODE> (není potřeba žádný parametr). | Funkce ''fork'' slouží k vytvoření procesu potomka, který je identický s rodičem. Rozlišení mezi rodičem a potomkem je možné pomocí testování návratového kódu funkce ''fork''. Rodič získá po návratu funkce PID procesu potomka. Potomek získá jako návratový kód 0 (nulu), protože si může zjistit svoje PPID (Parent PID, tj. číslo procesu rodiče) pomocí funkce <CODE>getppid()</CODE> (není potřeba žádný parametr). | ||
Řádka 32: | Řádka 36: | ||
V níže uvedeném programu se řádky 12 až 15 budou provádět jen v procesu potomka a řádky 17 až 24 jen v rodičovském procesu, přičemž kód na řádcích 17 až 18 bude proveden jen v případě neúspěchu funkce ''fork''. Neúspěšný návrat z funkce ''fork'' nastane pouze v neobvyklých případech, například při vyčerpání povoleného množství procesů pro přihlášeného uživatele nebo při celkovém zahlcení celého systému (například z důvodu vyčerpání dostupné paměti, vyčerpání maximálního počtu současně spustitelných procesů a podobně). | V níže uvedeném programu se řádky 12 až 15 budou provádět jen v procesu potomka a řádky 17 až 24 jen v rodičovském procesu, přičemž kód na řádcích 17 až 18 bude proveden jen v případě neúspěchu funkce ''fork''. Neúspěšný návrat z funkce ''fork'' nastane pouze v neobvyklých případech, například při vyčerpání povoleného množství procesů pro přihlášeného uživatele nebo při celkovém zahlcení celého systému (například z důvodu vyčerpání dostupné paměti, vyčerpání maximálního počtu současně spustitelných procesů a podobně). | ||
− | + | <source lang="C"> | |
− | + | #include <stdlib.h> | |
− | + | #include <stdio.h> | |
− | + | #include <unistd.h> | |
− | + | #include <sys/types.h> | |
− | + | #include <sys/wait.h> | |
− | + | int main () | |
− | + | { | |
− | + | pid_t pid; | |
− | + | int retcode; | |
− | + | pid = fork(); | |
− | + | if (pid == 0) { | |
− | + | printf("Potomek...\n"); | |
− | + | sleep(1); | |
− | + | printf("Potomek skoncil\n"); | |
− | + | exit(99); | |
− | + | } else if (pid < 0) { | |
− | + | printf("Fork selhal\n"); | |
− | + | exit(2); | |
− | + | } else { | |
− | + | printf("Rodic zna PID potomka: %d...a ceka na jeho konec\n",pid); | |
− | + | wait(&retcode); | |
− | + | printf("Potomek skoncil s kodem: %d\n",WEXITSTATUS(retcode)); | |
− | + | printf("Rodic konci\n"); | |
− | + | exit(3); | |
− | + | } | |
− | + | exit(1); | |
+ | } | ||
+ | </source> | ||
== Cvičení == | == Cvičení == | ||
Řádka 69: | Řádka 75: | ||
;Příklad 4: Napište síťového démona, který po připojení klienta odštěpí potomka, který klienta obslouží. Klient bude reagovat na jakýkoliv vstup pouze vlastní identifikací. | ;Příklad 4: Napište síťového démona, který po připojení klienta odštěpí potomka, který klienta obslouží. Klient bude reagovat na jakýkoliv vstup pouze vlastní identifikací. | ||
+ | |||
+ | [[Kategorie:Jazyk C v Linuxu]] |
Aktuální verze z 6. 4. 2009, 20:41
Vznik nových procesů je v unixových systémech spojen se dvěma funkcemi – fork()
a exec()
. Nejprve se blíže podíváme na rodinu funkcí exec, kterých je několik. Liší se způsobem, jakým jsou jim předávány parametry, možnostmi v zadávání parametrů a způsobem spuštění nového procesu. Jejich společným principem je nahrazení právě vykonávaného programu programem jiným, který je načten do stejného paměťového prostoru. Tím dojde k plnému nahrazení běžícího programu. Zachován zůstane PCB (Process Control Block), tj. např. PID (Process IDentification), práva souboru a také otevřené soubory a proměnné prostředí. Při volání funkce exec je potřeba na tyto okolnosti dávat pozor. Nejčastější chybou bývají zapomenuté otevřené deskriptory souborů nebo nežádoucí proměnné prostředí.
V následujícím příkladu je použita funkce execl()
, která vyžaduje, aby spouštěný program byl zadán s plnou cestou a je možné předávat přepínače a parametry jako na příkazovém řádku v shellu.
#include <stdio.h>
#include <unistd.h>
int main ()
{
int ret;
printf("Start... execl /bin/ls\n");
ret = execl ("/bin/ls", "ls", "-l", (char *)0);
printf("Chyba: navrat uz nebude\n");
return 1;
}
Další příklad používá funkci execle()
, která umožňuje nastavit proměnné prostředí. Nedojde tedy k dědění proměnných prostředí z rodiče, což může být užitečné v případech, kdy by mohlo dojít k nežádoucímu ovlivnění nově spuštěného programu. Na řádku 6 jsou připravené proměnné prostředí HOME a LOGNAME. Pomocí funkce execle se následně spustí příkaz printenv
, který vypíše všechny proměnné prostředí. Po spuštění programu budou ve výpisu jen výše zmíněné 2 proměnné HOME
a LOGNAME
. Pokud byste zkusili stejný příkaz spustit v předchozím příkladu, bude vypsáno nepoměrně více proměnných prostředí, které jsou při použití execl zděděny od rodiče.
#include <stdio.h>
#include <unistd.h>
int main ()
{
int ret;
char *env[] = { "HOME=/usr/home", "LOGNAME=home", (char *)0 };
printf("Start... exec /usr/bin/printenv\n");
ret = execle ("/usr/bin/printenv", (char *)0, env);
printf("Chyba: navrat uz nebude\n");
return 1;
}
Funkce fork slouží k vytvoření procesu potomka, který je identický s rodičem. Rozlišení mezi rodičem a potomkem je možné pomocí testování návratového kódu funkce fork. Rodič získá po návratu funkce PID procesu potomka. Potomek získá jako návratový kód 0 (nulu), protože si může zjistit svoje PPID (Parent PID, tj. číslo procesu rodiče) pomocí funkce getppid()
(není potřeba žádný parametr).
V níže uvedeném programu se řádky 12 až 15 budou provádět jen v procesu potomka a řádky 17 až 24 jen v rodičovském procesu, přičemž kód na řádcích 17 až 18 bude proveden jen v případě neúspěchu funkce fork. Neúspěšný návrat z funkce fork nastane pouze v neobvyklých případech, například při vyčerpání povoleného množství procesů pro přihlášeného uživatele nebo při celkovém zahlcení celého systému (například z důvodu vyčerpání dostupné paměti, vyčerpání maximálního počtu současně spustitelných procesů a podobně).
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main ()
{
pid_t pid;
int retcode;
pid = fork();
if (pid == 0) {
printf("Potomek...\n");
sleep(1);
printf("Potomek skoncil\n");
exit(99);
} else if (pid < 0) {
printf("Fork selhal\n");
exit(2);
} else {
printf("Rodic zna PID potomka: %d...a ceka na jeho konec\n",pid);
wait(&retcode);
printf("Potomek skoncil s kodem: %d\n",WEXITSTATUS(retcode));
printf("Rodic konci\n");
exit(3);
}
exit(1);
}
Cvičení
- Příklad 1
- Napište program démon, který se zbaví svého rodiče (rodičem se stane proces init) a odpojí se od terminálu.
- Příklad 2
- Napište démona, který neodpojí od terminálu svůj výstup a po přijetí signálu vypíše hlášení.
- Příklad 3
- Napište obdobu programu nohup.
- Příklad 4
- Napište síťového démona, který po připojení klienta odštěpí potomka, který klienta obslouží. Klient bude reagovat na jakýkoliv vstup pouze vlastní identifikací.