Procesy i wątki

Proces

Proces to swojego rodzaju logiczny kontener, który zawiera m.in.:

  • Listę wątków
  • Mapę pamięci procesu
  • Uchwyty do otwartych plików, połączeń sieciowych, urządzeń itp.
  • Dodatkowe informacje potrzebne systemowi do zarządzania danym procesem
  • Obsługę sygnałów, procesów potomnych

Wydzielenie takie – w postaci procesu, daje systemowi operacyjnemu możliwość zarządzania uruchomionymi programami. Scheduler systemowy (planista) przydziela czas procesora poszczególnym procesom uruchomionym w systemie. Konieczność przełączania pomiędzy procesami spowodowana jest tym, że danej chwili rdzeń procesora może wykonywać jeden wątek. Z punktu widzenia procesora na komputerze wykonywany jest jeden program, a z punktu widzenia systemu jednocześnie wykonywanych jest wiele programów. 

Współczesne procesory mogą wykonywać kilka wątków równocześnie, w zależności od liczby rdzeni. W tym momencie warto zauważyć, że proces po uruchomieniu posiada przynajmniej jeden wątek, z poziomu którego programowo można utworzyć kolejne. Wątek jest odpowidzialny za wykonywanie kodu programu.

Uruchomienie aplikacji powoduje utworzenie w systemie nowego procesu. Wyjątkiem może być np. Skrypt Java Script uruchomiony w przeglądarce, gdzie interpreter jest współdzielony przez wiele skryptów. Każdy proces ma wydzieloną przestrzeń adresową, która jest zapełniania i zwalniana podczas działania programu. Dostęp do tej pamięci przez inne procesy jest ograniczony. Proces zawiera także informacje zarządzane przez system operacyjny np.: identyfikator PID; czas życia uptime; ścieżka do katalogu roboczego; lista otwartych uchwytów; priorytet; lista argumentów.

Tworzenie procesu

Poniżej przedstawiam prosty przykład tworzenia nowego procesu z wykorzystaniem niskopoziomowego API systemów unixowych. Użyta została funkcja fork, która wykonuje kopię obecnego procesu.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>


int main(void)
{
    pid_t pid = fork();
    if(pid == 0)
    {
        //Kod procesu dziecka
        printf("Child Process\n");
    }
    else if(pid > 0)
    {
        //Kod procesu rodzica
        printf("Parent Process\n");
    }
    else
    {
        //Błąd
        perror("Failed to create process\n");
    }

    return 0;
}

Kompilacja i uruchomienie:

gcc -Wall -Wextra fork.c
./a.out
Parent Process
Child Process

Wątek

Wątek w praktyce jest jednostką wykonującą kod programu. Programiści tworzą wiele wątków działających w obrębie jednego procesu w celu uproszczenia struktury/architektury programu, wydzielenia logicznych części programu oraz zwiększenie wydajności przez zrównokeglenie obliczeń. 


Różnica pomiędzy wątkiem a procesem polega na tym, że wątki w obrębie tego samego procesu współdzielą między sobą pamięć adresową, uchwyty do urządzeń, plików, połączeń (proces ma przydzielone niezależne zasoby).Dzięki temu wymagają mniej zasobów do działania, krótszy jest ich czas tworzenia/zakończenia, komunikacja/współdzielenie zasobów może odbywać się bez pomocy jądra systemu oraz możliwość szybkiego przełączania kontekstu pomiędzy wątkami tego samego procesu. Możliwość jednoczesnego wykonywania kodu korzystającego z tych samych zasobów wymaga zapewnienia zsynchronizowanego dostępu do danych w celu uniknięcia błędów w obliczeniach, zakleszczenia wątków czy błędów bezpieczeństwa.

Tworzenie wątków

Poniżej przykład utworzenia nowych wątków z wykorzystaniem API zgodnego z POSIX.

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

void *thread_print(void *data);

int main(void)
{
    pthread_t th1, th2;
    int ret1, ret2;

    ret1 = pthread_create(&th1, NULL, thread_print, (void *)"Message 1");
    if(ret1 != 0)
    {
        fprintf(stderr, "Error: creating thread\n");
        return 1;
    }

    ret2 = pthread_create(&th2, NULL, thread_print, (void *)"Message 2");
    if(ret2 != 0)
    {
        fprintf(stderr, "Error: creating thread\n");
        return 1;
    }

    pthread_join(th1, NULL);
    pthread_join(th2, NULL);

    return 0;
}

void *thread_print(void *data)
{
    char *msg = (char *)data;
    printf("%s\n", msg);
    return NULL;
}

Kompilacja i uruchomienie: 

gcc -Wall -Wextra thread.c -lpthread
./a.out
Message 1
Message 2

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *