background image

05

Metodyka i Techniki Programowania II
Procesy i wątki
J. Dańda (modyfikacja ćwiczenia R. Stankiewicza)

12.03.2009

Wszystkie ćwiczenia należy wykonać w systemie UNIX/Linux.

Po zakończeniu zajęć odpowiedzi na 1, 2, 3 należy udzielać bez pomocy komputera.

Ćwiczenie 1 Lista procesów

Opisz efekt działania komendy  ps. Opisz następujące opcje komendy  ps:  -a,  a,  -e,  -f,  -u,  -x. Co 

oznaczają następujące pola: CMD, PID, PPID, STAT?

Ćwiczenie 2 Procesy w tle

Uruchom program  sleep  z parametrem  600. Wyślij do niego sygnał  TSTP. Jak wysłać taki sygnał? 
Uruchom jeszcze raz program  sleep  z parametrem  200  i również wyślij do niego  TSTP, a następnie 

uruchom polecenie „sleep 100 &”. Co oznacza „&”? Wyświetl swoje zadania za pomocą  jobs. Które 
zadania się wykonują, a które nie? Użyj poleceń bg i fg, żeby odpowiednio uruchamiać zadania w tle i 

na pierwszym planie.

Ćwiczenie 3 Sygnały

Do czego służy polecenie  kill? Uruchom  kill  z opcją  –l. Spróbuj wysłać sygnały  HUP,  INT,  TSTP, 
QUIT,  KILL,  TERM  za   pomocą   tego   polecenia   do   programu  sleep  uruchomionego   w   tle.   Następnie 

uruchom drugie okno konsoli,  uruchom w nim program  vi, a następnie z pierwszego okna spróbuj 
wysłać   do  niego  sygnał  INT.  Czy  vi  reaguje tak samo na  INT, jak  sleep? Napisz program, który 

przechwytuje sygnał INT i nie przerywa swojego działania (użyj signal()).

Ćwiczenie 4 fork()

Uruchom program. Wyjaśnij kod i działanie programu.

#include <stdio.h>

#include <unistd.h>
int main()

{
    int a;

    switch((a=fork()))
    {

          case -1:
                  /* fork nie zadzialal */

                  printf("Ups.\n");
                  break;

          case 0:
                  /* kod procesu potomnego */

                  printf("Dzieciak: rodzicem jest proces o pid=%d\n", getppid());
                  printf("Dzieciak: moj PID=%d\n", getpid());

                  sleep(60);
                  printf("Dzieciak: do widzenia.\n");

                  _exit(0);
                  break;

          default:
                  printf("Rodzic: fork zwrocil PID dzieciaka: %d\n", a);

                  sleep(30);
                  printf("Rodzic: do widzenia.\n");

                  _exit(0);
                  break;

    }
    return 0;

}

Uruchom   program   w   tle.   Sprawdź,   ile   powstało   procesów   o   tej   nazwie,   do   której   skompilowałeś 

program,   jakie   mają   identyfikatory  PID  i  PPID.   Zwróć   też   uwagę   na  PID  shell’a.   Poczekaj   na 
zakończenie rodzica i sprawdź jeszcze raz. Czy proces potomny powinien kończyć się po rodzicu? Kiedy 
fork() może zwrócić -1?

background image

Ćwiczenie 5 wait()

Program   z   ćwiczenia   4   zmodyfikuj   tak,   żeby   rodzic   przy   pomocy  wait()  czekał   na   zakończenie 

procesów   potomnych.   Zakończ   proces   potomny   przy   pomocy  kill.   Wykorzystaj  WIFEXITED()  i 
WTERMSIG(), żeby wyświetlić w sekcji rodzica informacje o zakończeniu procesu potomnego. 

Ćwiczenie 6 execl()

Uruchom program. Wyjaśnij kod i działanie programu. 

#include <fcntl.h>
#include <stdio.h>

#include <stdlib.h>
#include <unistd.h>

int main()
{

        printf("Program do podmiany kodu.\n");
        sleep(2);

        printf("Podmieniam kod.\n");
        execl("/bin/ls", "ls", 0);

        execl("/bin/date", "date", 0);
        printf("Czesc.\n");

        return 2;
}

Czy drugie wywołanie  execl() ma sens? Usuń „/bin/” w ścieżkach, skompiluj, wykonaj program. Co 
się zmieniło?

Umieść w bieżącym katalogu plik z kodem (poniżej), który skompiluj do nazwy „nowy”. Linijkę execl("/
bin/ls", "ls", 0); zamień na execl("nowy", "totamto", 0); . Uśpij program po podmianie kodu. 

Użyj ps, co się zmieniło?

#include <stdio.h>

#include <unistd.h>
int main()

{

printf("Ide spac.\n");

sleep(15);
printf("Koncze.\n");

return 0;

}

Zmodyfikuj kod tak, żeby wyświetlał pid rodzica.

Ćwiczenie 7 Wątki

Skompiluj poniższy kod (z opcją –pthread), wykonaj i wytłumacz go. 

#include <stdio.h>

#include <pthread.h>
#include <pthread.h>

struct dane {

        int numer;
        int czas;

};

void *procedura_watku(void *dane_przekazane_do_watku){
        struct dane *d = (struct dane *) dane_przekazane_do_watku;

        int i;
        printf("Poczatek watku nr %d.", d->numer);

        for (i=0; i<d->czas; i++)
        {

                printf("Watek: spie w petli %i.\n", i+1);
                sleep(2);

        }
        printf("Koniec watku nr %d\n", d->numer);

        return;
}

main(){

background image

        pthread_t watek_id;
        int i;

        struct dane a;
        a.numer = 1;

        a.czas = 5;
        printf("Uruchamiam watek.\n");

        pthread_create(&watek_id, NULL, procedura_watku, &a);
        sleep(1);

        for (i=0; i<5; i++)
        {

                printf("Glowny: spie w petli %i.\n", i+1);
                sleep(3);

        }
        printf("Koniec programu.\n");

        return;
}

Zmień powyższy kod tak, aby wątek spał łącznie 20 sekund. Sprawdź, co się dzieje. Następnie wymuś, 
żeby program główny czekał na zakończenie wątku przy pomocy pthread_join().

* Ćwiczenie 8 waitpid()

Zamiast wait() w ćwiczeniu 5 użyj waitpid(); efekt działania programu ma być taki sam. 

* Ćwiczenie 9 Wątki

Napisz   program,   który   co   sekundę   próbuje   wyświetlić   bieżącą   datę   i   jednocześnie,   niezależnie   od 

programu głównego, co sekundę wysyła pakiety ICMP do adresu IP będącego argumentem wywołania 
programu. Użyj system() oraz sprintf(). 

 


Document Outline