[C++] Procesy potomne


(system) #1

Witam

Mam taki problem. Potrzebuje wykorzystać funkcję fork w programie ale jest mały problem.

Program ma działać tak:

  1. Podajemy z wiersza poleceń argumenty do programu (chodzi o pliki) - dużo ich będzie

  2. Następnie proces macierzysty wywołuje proces potomny ale tak żeby proces ten przetworzył tylko JEDEN z plików podanych jako argument. Później kolejny raz wywołuję i kolejny plik.

  3. Proces potomny ma zwracać wartość do programu macierzystego.

Jak wywołać proces potomny i rozróżnić do od macierzystego to wiem. Ale nie wiem jak powiedzieć programowi

"Ty, przetwórz pierwszy plik"

"A Ty teraz przetwórz drugi plik"

itd.

Ma ktoś jakiś pomysł?


(Marcin 110) #2

Może coś takiego pomoże:

for (int i = 1; i < argc; ++i)

   {

      if (fork() == 0)

         {

            przetwarzaj(argv[i]);

            break; // (lub return) żeby potomek nie kręcił się w tej samej pętli co rodzic

         }

   }

EDIT: Ajj... nie doczytałem do punktu 3. Musisz nawiązać jakąś komunikację międzyprocesową, np. przez łącza nienazwane (man pipe).


(etam) #3

http://www.yolinux.com/TUTORIALS/LinuxT ... tml#BASICS

A jeżeli działasz pod windowsem, to to samo co wyżej i http://sourceware.org/pthreads-win32/


(system) #4

Niestety, na studiach mam wytyczne, ma być fork.

Już złapałem, fork wykonuje kopię programu ale od momentu utworzenia tego procesu

for(int i=0;i
{

    if (x == 0)

    {

        printf("[%u]: Proces potomny %d\n",getpid(),i);

        break;

    }

    x = fork();

}

Wynik programu

[marcinob@stud ~]$ ./a.out 8 8 8 8 8 8 8

potomny 1

potomny 2

potomny 3

potomny 4

potomny 5

potomny 6

potomny 7

czyli w pierwszym przebiegu pętli kiedy i=0 tworzony jest proces potomny i dopiero od 1 przetwarzam . Jak widać pętla nie idzie od nowa (bo myślałem że tak jest) więc jestem w domu :wink:

-- Dodane 23.06.2010 (Śr) 17:30 --

A teraz mam pytanie co do wartości zwracanej przez proces potomny, jak ?


(Marcin 110) #5

Jeśli rezultatem procesu potomnego ma być liczba całkowita, to wystarczy funkcja wait/waitpid (przez status). W przeciwnym wypadku potrzeba będzie nawiązać komunikację (najprościej na pipe'ach).


(system) #6

W procesie potomnym przetwarzam paragony z pliku, proces potomny przetworzył przykładowo 125 paragonów i teraz mam zwrócić ilość paragonów które przetworzył do procesu macierzystego. Proces macierzysty ma wyświetlić to ile paragonów przetworzył proces potomny.

Próbowałem z waitpid(proces, stat, 0) i w zmiennej stat nie mam ilości paragonów. Próbowałem return ilosc, exit(ilosc) ale zawsze jakieś śmieci tam mam.


(Marcin 110) #7

jeśli stat zadeklarowałeś przez

int stat;

, to powinno wyglądać tak:

waitpid(pid, &stat, 0);

, gdyż waitpid/wait potrzebuje wskaźnika do inta.

BTW: Możesz użyć funkcji wait zamiast waitpid - w końcu i tak ją wywołasz tyle samo razy, a nie musisz zapamiętywać pidów procesów potomnych.


(system) #8

I tak mam. Zauważyłem że zwraca mi wartość

tyle_co_ja_chce*256


(Marcin 110) #9

http://linux.die.net/man/2/waitpid stoi, że powinieneś użyć flagi WEXITED w przypadku waitpid. wait natomiast zawsze informuje tylko o zakończonym procesie.

Aaa... musisz użyć makra WEXITSTATUS(stat), żeby dobrać się do kodu powrotu.


(Cinek Cnx) #10

Mam dla ciebie coś takiego i myśle, że po drobnych przeróbkach to rozwikła twój problem:

#include 

#include 

#include 

#include 

#include 

#include 

#include 


using namespace std;


int main(int argc, char *argv[])

{


for(int i = 1; i < argc; i++)

{

        pid_t potomek = fork();


        if(potomek == 0)

        {

               cout << "Tworze proces potomny dla parametru: " << argv[i] << endl;

               //w tym miejscu kod wykonany bedzie tylko przez jeden nowo stworzony wątek wiec uruchamiasz funkcję która odpala kolejny plik z parametru


               exit(0); //Wczesniej pobierz w procesie maciezystym przez getpid() jego pid i tutaj zwracaj. 

        }

}


for(int i = 1; i < argc; i++)

{

        wait(0);

}


}

Pisałem to na szybko więc mógł gdzieś wkraść się błąd ale myślę że będzie dobrze. Oczywiście tam trzeba dopisać pobieranie pid z procesu macierzystego i wykonywanie kolejnych plików podanych w parametrze w miejscu które oznaczyłem komentarzem. Polecam program skompilować i przetestować np z 3 parametrami (ala ma kota). Do kompilacji używałem g++


(system) #11

Zadanie już dawno wykonane.

Największy problem był ze zwracaniem wartości, wykorzystywałem waitpid ale dostawałem jakieś kosmiczne liczby, po przeanalizowaniu okazało się że wartość zwracana jest o 256 razy większa. Wystarczyło podzielić i wyszło.


(Marcin 110) #12

:lol: ... Ten kod chyba nie jest zbyt przenośny, co? Próbowałeś tego na BSD / Mac OS X / Solarisie? Przecież napisałem, żebyś użył WEXITSTATUS(stat). Oto kwałek :

# define WEXITSTATUS(status)	__WEXITSTATUS (__WAIT_INT (status))

__WEXITSTATUS znajduje się w

/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */

#define	__WEXITSTATUS(status)	(((status) & 0xff00) >> 8)

Tak akurat się złożyło i możesz polegać jedynie na tym, że ten szczegół implementacyjny nie ulegnie w najbliższym czasie zmianie. Poza tym, waitpid powróci nawet w przypadku, kiedy proces potomny został wstrzymany lub wznowiony przez system, dlatego trzeba zrobić coś takiego:

if WIFEXITED(stat) /* proces się zakończył */

{

   kod_powrotu = WEXITSTATUS(status);

}

else /* fałszywy alarm */

{

}