Я выясняю, как работают потоки с fork, и вот код, который я пытался понять. (простите за ошибки в коде)

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
void* f(int threadnum) {
    int i;
    i = fork();

    if (i == 0) {   // child process
        printf("(%d) child says hello\n", threadnum);
    } else {
        printf("(%d) parent[%d] says hello\n", threadnum, i);
        wait(NULL);
        int new = fork();
        if (new != 0){
            printf("(%d) parent[%d] says hello to grandchild\n", threadnum, new);
            wait(NULL);
        } else 
            printf("(%d) grandchild says hello\n", threadnum);
    }
}

 int main () 
{
    pthread_t pid[2]; 
    for (int i = 0; i < 2; i++) {
        pthread_create(&pid[i], NULL, f, (void *)i);
        printf("Thread created with id [%li]\n", pid[i]);
    }
    for (int i = 0; i < 2; i++){
        pthread_join(pid[i], NULL);
    }
    return 0;
}

И это результат, который я получил:

Thread created with id [663664384]
Thread created with id [655271680]
(1) parent[5690] says hello
(0) parent[5691] says hello
(1) child says hello
(1) parent[5692] says hello to grandchild
(0) child says hello
(1) grandchild says hello
(0) parent[5693] says hello to grandchild
(0) grandchild says hello

Я не вижу большой разницы в том, как потоки работают иначе, чем необходимость дважды разветвлять вызов f(). Если один поток выполняет exit(), как насчет всего процесса? Если один поток вызывает exec(), как насчет других потоков?

1
Kode.Error404 18 Ноя 2019 в 06:39
Связано с (возможно, дубликатом) stackoverflow.com/questions/6056903/multithreaded-fork
 – 
Jeremy Friesner
18 Ноя 2019 в 07:17
Ваш код вызывает неопределенное поведение, не возвращая допустимое значение из функции потока. Убедитесь, что у вас есть return 0; на каждом пути выхода из функции потока (если у вас нет полезного значения для возврата).
 – 
Jonathan Leffler
18 Ноя 2019 в 09:58
Обратите внимание, что процесс «внук» на самом деле является вторым братом по отношению к первому разветвленному процессу; у него тот же родительский процесс.
 – 
Jonathan Leffler
18 Ноя 2019 в 10:00
Если ваша программа использовала мьютексы, например, и единственный поток в разветвленном процессе должен использовать мьютекс, заблокированный другим потоком в предварительно разветвленном процессе, тогда процесс заблокирован — нет никакого способа освободить этот заблокированный мьютекс. Это одна из многих причин, по которым вы должны быть осторожны. Ваш код не использует мьютексы; это делает его проще.
 – 
Jonathan Leffler
18 Ноя 2019 в 10:12

1 ответ

Вы не увидите большой разницы в поведении с вашим текущим кодом. Основное различие между потоком и процессом заключается в расположении памяти.

Дочерний поток использует ту же виртуальную память, что и родительский, тогда как дочерний процесс имеет собственную копию виртуальной машины. Следовательно, вы можете увидеть разницу в поведении потока и вилки, вызывая exit() из разных мест вашего кода.

Если вы вызовете exit() из места, где родитель передает привет (по сути, из нового потока), процесс немедленно завершится, поскольку он использует ту же виртуальную машину. В то время как если exit() вызывается из ребенок говорит привет (имеется в виду из нового процесса), остальные операторы печати будут продолжаться, поскольку дочерний процесс имеет собственное пространство памяти.

2
Rohit Walavalkar 18 Ноя 2019 в 07:09