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?
Ć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(){
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().