#c #pthreads #fork
#c #pthreads #разветвление
Вопрос:
Я следую этому руководству о pthread
и fork
, но я не понимаю, как работает следующий код. Следующий код взят из https://github.com/angrave/SystemProgramming/wiki/Pthreads,-Part-2:-Usage-in-Practice
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
static pid_t child = -2;
void *sleepnprint(void *arg) {
printf("%d:%s starting up...n", getpid(), (char *) arg);
while (child == -2) {sleep(1);} /* Later we will use condition variables */
printf("%d:%s finishing...n",getpid(), (char*)arg);
return NULL;
}
int main() {
pthread_t tid1, tid2;
pthread_create(amp;tid1,NULL, sleepnprint, "New Thread One");
pthread_create(amp;tid2,NULL, sleepnprint, "New Thread Two");
child = fork();
printf("%d:%sn",getpid(), "fork()ing complete");
sleep(3);
printf("%d:%sn",getpid(), "Main thread finished");
pthread_exit(NULL);
return 0; /* Never executes */
}
8970:New Thread One starting up...
8970:fork()ing complete
8973:fork()ing complete
8970:New Thread Two starting up...
8970:New Thread Two finishing...
8970:New Thread One finishing...
8970:Main thread finished
8973:Main thread finished
- Является ли 8970 родительским процессом?
- На веб-сайте говорится, что у дочернего процесса был только один поток, значит ли это, что дочерний процесс не
sleepnprint
работает? - Зачем
8970:fork()ing complete
8973:fork()ing complete
печатать раньше8970:New Thread Two starting up...
? Являются ли порядок потоков и процессов случайным?
Комментарии:
1. Вы не можете изменить переменную (дочернюю) в одном потоке и просмотреть ее в другом потоке без надлежащей синхронизации.
2. Зачем вообще использовать fork(), если потоковая обработка доступна? Это дисфункциональная функция из эпохи до многопоточности.
Ответ №1:
Основной поток (функция main()) создает два потока с помощью функции pthread_create(), но поскольку они являются потоками, они являются частью одного и того же процесса (getpid() возвращает 8970 для основного потока и вторичных потоков). Если вам нужны идентификаторы задач, вызовите gettid() в точке входа потока (вы получите соответственно 8971 и 8972).
Затем отцовский процесс разветвляется, и оба отцовских и дочерних процесса продолжаются в функции main(). Они соответственно отображают свои pid: 8970 и 8973.
Когда многопоточный процесс разветвляется, в дочернем процессе «воспроизводится» только вызывающий поток (другие потоки родительского процесса не разветвляются: дочерний процесс является однопоточным, пока не создаст новые потоки на своей стороне). Итак, в вашем примере дочерний процесс с номером 8973 не имеет двух потоков, созданных в родительском процессе (номер 8970).
Да, все потоки и процессы выполняются параллельно (в любом порядке).
Чтобы проиллюстрировать предыдущее, вот немного улучшенная версия вашей программы:
#define _GNU_SOURCE // To get gettid()
#include <pthread.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
static volatile pid_t child = -2;
void *sleepnprint(void *arg)
{
printf("Process %d, Task %d:%s starting up...n", getpid(), gettid(), (char *) arg);
// This is not the best way to synchronize threads but this works here:
// once the main thread returns from fork(), child = pid of child process
// (i.e. != -2)
while (child == -2) {sleep(1);} /* Later we will use condition variables */
printf("Process %d, Task %d:%s finishing...n", getpid(), gettid(), (char*)arg);
return NULL;
}
int main() {
pthread_t tid1, tid2;
pthread_create(amp;tid1,NULL, sleepnprint, "New Thread One");
pthread_create(amp;tid2,NULL, sleepnprint, "New Thread Two");
child = fork();
// In father process: child = child process pid
// In child process: child = 0
if (child == 0) {
// This is the child process
printf("%d:%sn",getpid(), "Child process finished");
exit(0);
}
// Father process
printf("%d:%sn",getpid(), "fork()ing complete");
sleep(3);
printf("%d:%sn",getpid(), "Main thread finished");
pthread_exit(NULL);
return 0; /* Never executes */
}
Компиляция и выполнение:
$ gcc example.c -l pthread
$ ./a.out
Process 6141, Task 6142:New Thread One starting up...
Process 6141, Task 6142:New Thread One finishing...
Process 6141, Task 6143:New Thread Two starting up...
Process 6141, Task 6143:New Thread Two finishing...
6144:Child process finished
6141:fork()ing complete
6141:Main thread finished