20-bo‘lim

Amaliy loyiha - mini qobiq

Butun kursda o'rganilgan bilimlarni birlashtirib, ishlaydigan qobiq yozamiz: buyruq tahlili, fork/exec, konveyerlar, yo'naltirish va signallar.

🕑 14 daqiqa o‘qish 📄 687 so‘z 👁 3 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Nima quramiz
  2. 1-qadam: buyruqni tahlil qilish
  3. 2-qadam: buyruqni bajarish
  4. 3-qadam: yo'naltirish
  5. 4-qadam: konveyer
  6. 5-qadam: ichki buyruqlar
  7. 6-qadam: signallarni boshqarish
  8. To'liq qobiq
  9. Keyingi qadamlar
  10. Xulosa

Yigirma bo'lim davomida o'rgangan hamma narsani bitta dasturda birlashtiramiz. Qobiq - operatsion tizim bilan ishlashning eng yaxshi mashqi.

Nima quramiz #

Qobiqning asosiy sikli 1. Belgini chiqarish 2. Qatorni o'qish 3. Tahlil qilish 4. Bajarish 5. Kutish takrorlash Tahlil nimani ajratadi Buyruq va argumentlar Konveyer belgisi | Yo'naltirish > va < Fon belgisi & Ichki buyruqlar
Har bosqichda kursning ma'lum bo'limi ishlatiladi
ImkoniyatQaysi bo'limdan
Buyruq bajarish4 - jarayon yaratish
Konveyer15 - jarayonlararo aloqa
Yo'naltirish12, 15 - fayllar va dup2
Ctrl+C boshqaruvi16 - signallar
Fon jarayonlari3, 16 - jarayonlar va SIGCHLD
Zombi larni yig'ish4, 16 - waitpid

1-qadam: buyruqni tahlil qilish #

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_ARG  64

/* Qatorni bo'shliqlar bo'yicha argumentlarga ajratadi */
static int tahlil(char *qator, char **argv, int maks) {
    int soni = 0;
    char *belgi = strtok(qator, " \t\n");

    while (belgi != NULL && soni < maks - 1) {
        argv[soni++] = belgi;
        belgi = strtok(NULL, " \t\n");
    }

    argv[soni] = NULL;

    return soni;
}

int main(void) {
    char qator[] = "ls -la /home  ";
    char *argv[MAX_ARG];

    int soni = tahlil(qator, argv, MAX_ARG);

    printf("Argumentlar soni: %d\n", soni);

    for (int i = 0; i < soni; i++) {
        printf("  argv[%d] = \"%s\"\n", i, argv[i]);
    }

    printf("  argv[%d] = NULL\n", soni);
    printf("\nexecvp uchun tayyor: %s\n", argv[soni] == NULL ? "ha" : "yo'q");

    return 0;
}
Natija
Argumentlar soni: 3
  argv[0] = "ls"
  argv[1] = "-la"
  argv[2] = "/home"
  argv[3] = NULL

execvp uchun tayyor: ha
Nima uchun oxirida NULL

execvp(argv[0], argv) massiv qayerda tugashini bilishi kerak. Uzunlik uzatilmagani uchun NULL ko'rsatkichi chegara belgisi bo'ladi.

NULL qo'yishni unutsangiz, exec massivdan tashqariga chiqib o'qiydi - natija aniqlanmagan xatti-harakat.

strtok bilan ehtiyot bo'ling: u asl qatorni o'zgartiradi (ajratuvchilar o'rniga \0 qo'yadi) va ichida global holat saqlaydi. Ko'p oqimli kodda strtok_r ishlating.

2-qadam: buyruqni bajarish #

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>

static int bajarish(char **argv) {
    fflush(stdout);

    pid_t bola = fork();

    if (bola < 0) {
        perror("fork");
        return -1;
    }

    if (bola == 0) {
        execvp(argv[0], argv);

        /* Bu yerga yetsak - exec muvaffaqiyatsiz */
        fprintf(stderr, "%s: buyruq topilmadi\n", argv[0]);
        fflush(stderr);
        _exit(127);
    }

    int holat;
    waitpid(bola, &holat, 0);

    return WIFEXITED(holat) ? WEXITSTATUS(holat) : -1;
}

int main(void) {
    char *echo_argv[] = { "echo", "salom dunyo", NULL };
    char *yolgon_argv[] = { "bunday_buyruq_yoq_12345", NULL };

    int birinchi = bajarish(echo_argv);
    printf("echo chiqish kodi: %d\n", birinchi);

    int ikkinchi = bajarish(yolgon_argv);
    printf("Topilmagan buyruq kodi: %d\n", ikkinchi);
    printf("127 mi? %s\n", ikkinchi == 127 ? "ha - qobiq an'anasi" : "yo'q");

    return 0;
}
Natija
salom dunyo
echo chiqish kodi: 0
bunday_buyruq_yoq_12345: buyruq topilmadi
Topilmagan buyruq kodi: 127
127 mi? ha - qobiq an'anasi
Qobiqning chiqish kodlari an'anasi
KodMa'nosi
0Muvaffaqiyat
1-125Dasturning o'z xatosi
126Fayl topildi, lekin bajarib bo'lmadi
127Buyruq topilmadi
128 + NN signali bilan tugatildi

Shuning uchun Ctrl+C (SIGINT = 2) bilan to'xtatilgan dastur 130 qaytaradi, SIGKILL (9) esa 137.

Terminal
sleep 100
# Ctrl+C bosamiz
echo $?
Natija
130

19-bo'limdagi Docker ning Exit Code 137 aynan shu: 128 + 9 = SIGKILL.

3-qadam: yo'naltirish #

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>

/* argv dan > va < belgilarini ajratib oladi */
static void yonaltirishni_ajratish(char **argv, char **chiqish, char **kirish) {
    *chiqish = NULL;
    *kirish = NULL;

    for (int i = 0; argv[i] != NULL; i++) {
        if (strcmp(argv[i], ">") == 0 && argv[i + 1] != NULL) {
            *chiqish = argv[i + 1];
            argv[i] = NULL;
            return;
        }

        if (strcmp(argv[i], "<") == 0 && argv[i + 1] != NULL) {
            *kirish = argv[i + 1];
            argv[i] = NULL;
            return;
        }
    }
}

int main(void) {
    char *argv[] = { "echo", "faylga yozildi", ">", "/tmp/qobiq_sinov.txt", NULL };
    char *chiqish;
    char *kirish;

    yonaltirishni_ajratish(argv, &chiqish, &kirish);

    printf("Buyruq       : %s\n", argv[0]);
    printf("Chiqish fayli: %s\n", chiqish != NULL ? chiqish : "(yo'q)");

    fflush(stdout);

    pid_t bola = fork();

    if (bola == 0) {
        if (chiqish != NULL) {
            int fd = open(chiqish, O_WRONLY | O_CREAT | O_TRUNC, 0644);

            if (fd < 0) {
                _exit(1);
            }

            dup2(fd, STDOUT_FILENO);
            close(fd);
        }

        execvp(argv[0], argv);
        _exit(127);
    }

    waitpid(bola, NULL, 0);

    /* Natijani o'qib ko'ramiz */
    FILE *f = fopen("/tmp/qobiq_sinov.txt", "r");
    char bufer[64] = "";

    if (f != NULL) {
        if (fgets(bufer, sizeof bufer, f) == NULL) {
            bufer[0] = '\0';
        }

        fclose(f);
    }

    bufer[strcspn(bufer, "\n")] = '\0';

    printf("Fayl mazmuni : %s\n", bufer);
    printf("To'g'rimi?   : %s\n",
           strcmp(bufer, "faylga yozildi") == 0 ? "ha" : "yo'q");

    unlink("/tmp/qobiq_sinov.txt");

    return 0;
}
Natija
Buyruq       : echo
Chiqish fayli: /tmp/qobiq_sinov.txt
Fayl mazmuni : faylga yozildi
To'g'rimi?   : ha

4-qadam: konveyer #

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>

/* Ikki buyruqni quvur bilan bog'lab bajaradi */
static int konveyer(char **chap, char **ong) {
    int quvur[2];

    if (pipe(quvur) < 0) {
        return -1;
    }

    fflush(stdout);

    pid_t birinchi = fork();

    if (birinchi == 0) {
        close(quvur[0]);
        dup2(quvur[1], STDOUT_FILENO);
        close(quvur[1]);

        execvp(chap[0], chap);
        _exit(127);
    }

    pid_t ikkinchi = fork();

    if (ikkinchi == 0) {
        close(quvur[1]);
        dup2(quvur[0], STDIN_FILENO);
        close(quvur[0]);

        execvp(ong[0], ong);
        _exit(127);
    }

    /* Ota ikkala uchni ham yopishi SHART */
    close(quvur[0]);
    close(quvur[1]);

    int holat;
    waitpid(birinchi, NULL, 0);
    waitpid(ikkinchi, &holat, 0);

    return WIFEXITED(holat) ? WEXITSTATUS(holat) : -1;
}

int main(void) {
    char *chap[] = { "printf", "olma\\nanor\\nolcha\\n", NULL };
    char *ong[] = { "grep", "-c", "^ol", NULL };

    printf("Bajarilmoqda: printf ... | grep -c \"^ol\"\n");
    fflush(stdout);

    int kod = konveyer(chap, ong);

    printf("Chiqish kodi: %d\n", kod);
    printf("grep mos qator topdimi? %s\n", kod == 0 ? "ha" : "yo'q");

    return 0;
}
Natija
Bajarilmoqda: printf ... | grep -c "^ol"
2
Chiqish kodi: 0
grep mos qator topdimi? ha
Konveyerda ota ikkala uchni yopishi shart

Bu eng ko'p uchraydigan xato:

C
/* NOTO'G'RI - ota quvur[1] ni ochiq qoldirdi */
waitpid(ikkinchi, NULL, 0);      /* abadiy kutish */

grep fayl oxirini kutadi. Fayl oxiri esa barcha yozish uchlari yopilganda keladi.

Ota quvur[1] ni ochiq qoldirsa, grep hech qachon EOF olmaydi va qobiq qotib qoladi.

Qoida: fork lardan keyin ota darhol ikkala uchni yopadi - unga quvur kerak emas, u faqat bolalarga uzatgan edi.

Uch bosqichli konveyerda (a | b | c) bu yanada muhim: har bir oraliq quvurni hamma keraksiz jarayonda yopish kerak.

5-qadam: ichki buyruqlar #

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

/* Ichki buyruq bo'lsa bajarib 1 qaytaradi */
static int ichki_buyruq(char **argv) {
    if (argv[0] == NULL) {
        return 1;
    }

    if (strcmp(argv[0], "cd") == 0) {
        const char *yol = argv[1] != NULL ? argv[1] : getenv("HOME");

        if (yol == NULL || chdir(yol) != 0) {
            printf("cd: katalogga o'tib bo'lmadi\n");
        }

        return 1;
    }

    if (strcmp(argv[0], "pwd") == 0) {
        char bufer[1024];

        if (getcwd(bufer, sizeof bufer) != NULL) {
            printf("%s\n", bufer);
        }

        return 1;
    }

    if (strcmp(argv[0], "exit") == 0) {
        printf("(chiqish)\n");
        return 1;
    }

    return 0;
}

int main(void) {
    char *cd_argv[] = { "cd", "/tmp", NULL };
    char *pwd_argv[] = { "pwd", NULL };
    char *ls_argv[] = { "ls", NULL };

    printf("cd ichki buyruqmi?  %s\n", ichki_buyruq(cd_argv) ? "ha" : "yo'q");
    printf("Joriy katalog      : ");
    ichki_buyruq(pwd_argv);

    printf("ls ichki buyruqmi?  %s\n", ichki_buyruq(ls_argv) ? "ha" : "yo'q");
    printf("Demak ls uchun fork/exec kerak\n");

    return 0;
}
Natija
cd ichki buyruqmi?  ha
Joriy katalog      : /tmp
ls ichki buyruqmi?  yo'q
Demak ls uchun fork/exec kerak
cd nima uchun alohida dastur bo'la olmaydi

Joriy katalog - jarayonning xossasi. fork qilingan bola uni o'zgartirsa, bu faqat bolaga ta'sir qiladi.

Natija
qobiq (PID 100, /home)
  └── cd dasturi (PID 101) - chdir("/tmp") qildi va o'ldi
qobiq hali ham /home da

Shuning uchun cd qobiqning o'zida bajarilishi shart.

Xuddi shu sababdan quyidagilar ham ichki buyruq:

BuyruqNima uchun ichki
cdJoriy katalog jarayon xossasi
exportMuhit o'zgaruvchisi meros qoladi
exitQobiqning o'zi tugashi kerak
umaskJarayon xossasi
ulimitJarayon chegaralari

Buni tekshirish oson:

Terminal
type cd
Natija
cd is a shell builtin

6-qadam: signallarni boshqarish #

C
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>

static volatile sig_atomic_t uzildi = 0;
static volatile sig_atomic_t yigilgan = 0;

static void sigint_ishlovchi(int r) {
    (void) r;
    uzildi = 1;
}

static void sigchld_ishlovchi(int r) {
    (void) r;

    int saqlangan = errno;

    while (waitpid(-1, NULL, WNOHANG) > 0) {
        yigilgan++;
    }

    errno = saqlangan;
}

int main(void) {
    struct sigaction sa;

    memset(&sa, 0, sizeof sa);
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;

    sa.sa_handler = sigint_ishlovchi;
    sigaction(SIGINT, &sa, NULL);

    sa.sa_handler = sigchld_ishlovchi;
    sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
    sigaction(SIGCHLD, &sa, NULL);

    printf("Qobiq signallarni sozladi:\n");
    printf("  SIGINT  - Ctrl+C qobiqni o'ldirmasin\n");
    printf("  SIGCHLD - fon jarayonlarini yig'ish\n");

    /* Ctrl+C simulyatsiyasi */
    raise(SIGINT);

    printf("\nCtrl+C keldi, qobiq tirikmi? %s\n", "ha");
    printf("Bayroq o'rnatildimi?         %s\n", uzildi ? "ha" : "yo'q");

    printf("\nMuhim: bola jarayonlar SIGINT ni ODATIY qabul qilishi kerak\n");
    printf("Shuning uchun fork dan keyin bolada:\n");
    printf("  signal(SIGINT, SIG_DFL);\n");

    return 0;
}
Natija
Qobiq signallarni sozladi:
  SIGINT  - Ctrl+C qobiqni o'ldirmasin
  SIGCHLD - fon jarayonlarini yig'ish

Ctrl+C keldi, qobiq tirikmi? ha
Bayroq o'rnatildimi?         ha

Muhim: bola jarayonlar SIGINT ni ODATIY qabul qilishi kerak
Shuning uchun fork dan keyin bolada:
  signal(SIGINT, SIG_DFL);
Ishlovchini bolaga meros qoldirmang

fork dan keyin bola otaning signal ishlovchilarini meros oladi. Agar qobiq SIGINT ni e'tiborsiz qoldirsa, sleep 100 ni ham Ctrl+C to'xtata olmaydi.

Bolada ishlovchini odatiy holatga qaytaring:

C
if (bola == 0) {
    signal(SIGINT, SIG_DFL);
    signal(SIGQUIT, SIG_DFL);
    signal(SIGTSTP, SIG_DFL);

    execvp(argv[0], argv);
    _exit(127);
}

Haqiqiy qobiqlar bundan ham ko'proq ish qiladi - ular jarayon guruhlari yaratib, terminalni o'sha guruhga topshiradi (tcsetpgrp). Shunda Ctrl+C butun konveyerga yetadi, faqat oxirgi buyruqqa emas.

To'liq qobiq #

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>

#define MAX_ARG   64
#define MAX_QATOR 1024

static volatile sig_atomic_t yigilgan = 0;

static void sigchld_ishlovchi(int r) {
    (void) r;

    int saqlangan = errno;

    while (waitpid(-1, NULL, WNOHANG) > 0) {
        yigilgan++;
    }

    errno = saqlangan;
}

static int tahlil(char *qator, char **argv, int maks) {
    int soni = 0;
    char *saqlash = NULL;
    char *belgi = strtok_r(qator, " \t\n", &saqlash);

    while (belgi != NULL && soni < maks - 1) {
        argv[soni++] = belgi;
        belgi = strtok_r(NULL, " \t\n", &saqlash);
    }

    argv[soni] = NULL;

    return soni;
}

/* argv ni | bo'yicha ikkiga bo'ladi; topilmasa NULL qaytaradi */
static char **konveyerni_ajratish(char **argv) {
    for (int i = 0; argv[i] != NULL; i++) {
        if (strcmp(argv[i], "|") == 0) {
            argv[i] = NULL;
            return &argv[i + 1];
        }
    }

    return NULL;
}

static void yonaltirish(char **argv) {
    for (int i = 0; argv[i] != NULL; i++) {
        int chiqishmi = strcmp(argv[i], ">") == 0;
        int kirishmi = strcmp(argv[i], "<") == 0;

        if ((chiqishmi || kirishmi) && argv[i + 1] != NULL) {
            int fd = chiqishmi
                   ? open(argv[i + 1], O_WRONLY | O_CREAT | O_TRUNC, 0644)
                   : open(argv[i + 1], O_RDONLY);

            if (fd >= 0) {
                dup2(fd, chiqishmi ? STDOUT_FILENO : STDIN_FILENO);
                close(fd);
            }

            argv[i] = NULL;
            return;
        }
    }
}

static void bolani_tayyorlash(void) {
    signal(SIGINT, SIG_DFL);
    signal(SIGQUIT, SIG_DFL);
}

static int ichki_buyruq(char **argv) {
    if (argv[0] == NULL) {
        return 1;
    }

    if (strcmp(argv[0], "cd") == 0) {
        const char *yol = argv[1] != NULL ? argv[1] : getenv("HOME");

        if (yol == NULL || chdir(yol) != 0) {
            fprintf(stderr, "cd: xato\n");
        }

        return 1;
    }

    if (strcmp(argv[0], "pwd") == 0) {
        char bufer[MAX_QATOR];

        if (getcwd(bufer, sizeof bufer) != NULL) {
            printf("%s\n", bufer);
        }

        return 1;
    }

    return 0;
}

static void bajarish(char **argv) {
    char **ong = konveyerni_ajratish(argv);

    if (ong == NULL) {
        if (ichki_buyruq(argv)) {
            return;
        }

        fflush(stdout);

        pid_t b = fork();

        if (b == 0) {
            bolani_tayyorlash();
            yonaltirish(argv);
            execvp(argv[0], argv);
            fprintf(stderr, "%s: buyruq topilmadi\n", argv[0]);
            fflush(stderr);
            _exit(127);
        }

        waitpid(b, NULL, 0);
        return;
    }

    /* Konveyer */
    int quvur[2];

    if (pipe(quvur) < 0) {
        return;
    }

    fflush(stdout);

    pid_t chap = fork();

    if (chap == 0) {
        bolani_tayyorlash();
        close(quvur[0]);
        dup2(quvur[1], STDOUT_FILENO);
        close(quvur[1]);
        yonaltirish(argv);
        execvp(argv[0], argv);
        _exit(127);
    }

    pid_t ong_pid = fork();

    if (ong_pid == 0) {
        bolani_tayyorlash();
        close(quvur[1]);
        dup2(quvur[0], STDIN_FILENO);
        close(quvur[0]);
        yonaltirish(ong);
        execvp(ong[0], ong);
        _exit(127);
    }

    close(quvur[0]);
    close(quvur[1]);

    waitpid(chap, NULL, 0);
    waitpid(ong_pid, NULL, 0);
}

int main(void) {
    struct sigaction sa;

    memset(&sa, 0, sizeof sa);
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
    sa.sa_handler = sigchld_ishlovchi;
    sigaction(SIGCHLD, &sa, NULL);

    signal(SIGINT, SIG_IGN);

    /* Sinov buyruqlari - haqiqiy qobiqda bu fgets(stdin) bo'ladi */
    const char *sinovlar[] = {
        "echo Salom, mini qobiq!",
        "cd /tmp",
        "pwd",
        "printf olma\\nanor\\nolcha\\n | grep -c ^ol",
        "echo faylga > /tmp/mq.txt",
        "cat /tmp/mq.txt",
        "bunday_buyruq_yoq"
    };

    char qator[MAX_QATOR];
    char *argv[MAX_ARG];

    for (size_t i = 0; i < sizeof sinovlar / sizeof sinovlar[0]; i++) {
        printf("mq$ %s\n", sinovlar[i]);
        fflush(stdout);

        strncpy(qator, sinovlar[i], sizeof qator - 1);
        qator[sizeof qator - 1] = '\0';

        tahlil(qator, argv, MAX_ARG);
        bajarish(argv);
    }

    unlink("/tmp/mq.txt");

    printf("mq$ exit\n");

    return 0;
}
Natija
mq$ echo Salom, mini qobiq!
Salom, mini qobiq!
mq$ cd /tmp
mq$ pwd
/tmp
mq$ printf olma\nanor\nolcha\n | grep -c ^ol
2
mq$ echo faylga > /tmp/mq.txt
mq$ cat /tmp/mq.txt
faylga
mq$ bunday_buyruq_yoq
bunday_buyruq_yoq: buyruq topilmadi
mq$ exit
Haqiqiy qobiqqa aylantirish

Yuqoridagi kod sinov buyruqlarini massivdan oladi. Interaktiv qilish uchun main dagi siklni almashtiring:

C
char qator[MAX_QATOR];
char *argv[MAX_ARG];

while (1) {
    printf("mq$ ");
    fflush(stdout);

    if (fgets(qator, sizeof qator, stdin) == NULL) {
        break;                       /* Ctrl+D */
    }

    if (tahlil(qator, argv, MAX_ARG) == 0) {
        continue;
    }

    if (strcmp(argv[0], "exit") == 0) {
        break;
    }

    bajarish(argv);
}

Buyruqlar tarixi va o'q tugmalari uchun readline kutubxonasini qo'shing:

C
#include <readline/readline.h>
#include <readline/history.h>

char *qator = readline("mq$ ");

if (qator != NULL && *qator) {
    add_history(qator);
}
Terminal
gcc -std=c17 -Wall qobiq.c -o qobiq -lreadline

Keyingi qadamlar #

Qobiqni rivojlantirish yo'nalishlari
ImkoniyatKerakli bilim
Ko'p bosqichli konveyer (a | b | c)Rekursiya yoki sikl
Fon jarayonlari (&)waitpid siz fork
jobs, fg, bgJarayon guruhlari, tcsetpgrp
>> qo'shib yozishO_APPEND
2> xato yo'naltirishdup2(fd, 2)
Qavslar va tirnoqlarTo'liq leksik tahlil
O'zgaruvchilar ($HOME)getenv, almashtirish
Fayl nomlarini to'ldirishglob()
&& va ``Chiqish kodini tekshirish
Skript fayllarini bajarishfopen + o'sha sikl

Har bir imkoniyat kursdagi biror bo'limga tayanadi. Bu loyihani bosqichma-bosqich kengaytirish - operatsion tizimlarni o'rganishning eng samarali usuli.

Amaliy topshiriq
  1. tahlil funksiyasini yozib, argumentlarga ajrating.
  2. fork va execvp bilan oddiy buyruqni bajaring.
  3. Topilmagan buyruq uchun 127 kodini qaytaring.
  4. > yo'naltirishni dup2 bilan amalga oshiring.
  5. < kirish yo'naltirishini qo'shing.
  6. Ikki buyruqli konveyer quring va ikkala uchni yoping.
  7. cd va pwd ichki buyruqlarini qo'shing.
  8. cd nima uchun alohida dastur bo'la olmasligini tushuntiring.
  9. SIGINT ni qobiqda e'tiborsiz, bolada odatiy qiling.
  10. & bilan fon jarayonini qo'shib, SIGCHLD bilan yig'ing.

Xulosa #

  • Qobiqning sikli: belgi → o'qish → tahlil → bajarish → kutish.
  • execvp uchun argumentlar massivi NULL bilan tugashi shart.
  • Ko'p oqimli kodda strtok emas, strtok_r ishlating.
  • Chiqish kodi 127 - buyruq topilmadi, 128+N - signal.
  • Yo'naltirish - open + dup2 + close.
  • Konveyerda ota ikkala uchni ham yopishi shart.
  • cd ichki buyruq bo'lishi kerak - joriy katalog jarayon xossasi.
  • Qobiq SIGINT ni e'tiborsiz qoldiradi, bola odatiy qabul qiladi.
  • SIGCHLD ishlovchisida while (waitpid(...)) ishlating.
  • Har bir yangi imkoniyat kursdagi biror bo'limga tayanadi.

Tabriklaymiz! Siz operatsion tizimlarning asosiy tushunchalarini o'rgandingiz: jarayonlar va oqimlar, rejalashtirish, sinxronizatsiya, xotira boshqaruvi va virtual xotira, fayl tizimlari, kiritish-chiqarish, jarayonlararo aloqa, signallar, xavfsizlik, yuklanish va virtualizatsiya - va hammasini bitta ishlaydigan dasturda birlashtirdingiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.