Визуально, что происходит, когда вы вызываете тот же процесс с амперсандом

Я играю с ampersand “&”. Я понимаю, что в сценарии оболочки bash

амперсанд используется для разветвления процессов, но будет работать в фоновом режиме. Это полезно, поскольку позволяет вам немедленно вернуться к подсказке и запустить процесс в фоновом режиме.

Пожалуйста, обратите внимание на следующий код:

#include <stdio.h>
#include <unistd.h>

int x=5;

void main()
{
   int pid = getpid();
   int y=6;

   printf("[%d] [%p] x = %d\n", pid, &x, x++);
   printf("[%d] [%p] y = %d\n", pid, &y, y++);
}

После успешной компиляции я запускаю код с помощью:

> ./a.out & ./a.out & ./a.out

Результаты первого запуска:

[4436] [0x601058] x = 5
[4435] [0x601058] x = 5
[4436] [0x7fff2d481bd8] y = 6
[4435] [0x7fff7ecadd88] y = 6
[4437] [0x601058] x = 5
[4437] [0x7fff6e0741d8] y = 6

Результаты второго запуска:

[4469] [0x601058] x = 5
[4469] [0x7fffa00048b8] y = 6
[4470] [0x601058] x = 5
[4470] [0x7fffd447a798] y = 6
[4468] [0x601058] x = 5
[4468] [0x7fffc35dc7b8] y = 6

Наблюдения:

  • Некоторые операторы печати отображаются в другом порядке, поскольку все процессы выполняются одновременно.
  • Адрес переменной x одинаков во всех экземплярах, потому что это глобальная переменная.
  • Значение x одинаково во всех случаях, потому что оно каждый раз сбрасывается до 5.
  • Переменная y локальна только для main(), поэтому ее адрес будет уникальным в каждом процессе.

Вот мои вопросы:

  1. Причина, по которой некоторые операторы печати появляются в другом порядке, определяется тем, какой процесс был запущен первым планировщиком ОС?
  2. Поскольку переменная x является глобальной и, кажется, сохраняет один и тот же адрес во всех запусках/экземплярах. Почему его значение не распределяется между процессами после автоинкремента? Почему НИ ОДИН процесс не печатает увеличенное значение x?

person lucidgold    schedule 10.11.2014    source источник
comment
Адреса памяти находятся в виртуальной памяти. Так как все процессы выполняют одну и ту же программу, их виртуальная память распределяется одинаково, поэтому у всех будет один и тот же адрес.   -  person Barmar    schedule 10.11.2014
comment
Похоже, вам нужно пройти курс по операционным системам, чтобы понять, как работает виртуальная память.   -  person Barmar    schedule 10.11.2014
comment
@Barmar: Спасибо, очень конструктивно.   -  person lucidgold    schedule 10.11.2014
comment
Даже без & процессы запускаются форком. Важное отличие состоит в том, что оболочка не ждет завершения дочернего процесса. (Есть и другие детали.)   -  person William Pursell    schedule 10.11.2014
comment
@WilliamPursell: Спасибо!   -  person lucidgold    schedule 10.11.2014


Ответы (1)


Каждый процесс имеет свой собственный адресное пространство в виртуальная память (благодаря MMU процессора). Таким образом, переменная x не является глобальной для ваших 3 процессов; каждый процесс имеет свой собственный x; поэтому адрес 0x601058 (распечатанный адрес x) в процессе 4436 не совпадает с «тот же» адрес 0x601058 в процессе 4435.

Таким образом, (виртуальная) память специфична для каждого процесса. Процесс может изменить свое адресное пространство с помощью mmap(2). Вы можете использовать некоторые продвинутые методы для настройки некоторой разделяемой памяти между несколькими процессами (но узнайте больше о Linux программирование раньше). См. раздел shm_overview(7) и sem_overview(7). Вы не должны (как новичок) использовать общую память из-за проблем с синхронизацией.

Прочитайте Advanced Linux Programming, в нем есть несколько глав, связанных с вашими вопросами.

Многопоточный процесс состоит из нескольких потоков, совместно использующих одинаковую адресное пространство (и другие вещи, такие как текущий каталог, дескрипторы открытых файлов и т. д.). Прочтите также руководство по теме POSIX (также известное как pthread). У каждого потока есть собственный стек вызовов.

Обратите внимание, что адреса могут не воспроизводиться от одного запуска к другому из-за ASLR.

ядро Linux имеет планировщик, работающий над задачами . Запланированная задача — это либо поток, либо (однопоточный) процесс. Планировщик может вытеснять задачи в произвольное время и на многоядерном процессоре. процессор у вас может быть несколько задач, работающих параллельно (на разных ядрах).

Вы также можете играть (в Linux) с proc(5). . Если вы позволите своим процессам спать, например. 10 секунд, вы можете ввести (например, в другом терминале) cat /proc/4436/maps, пока ваш процесс 4436 все еще работает (или спит).

Вы также можете поиграть с strace(1), возможно, попробуйте strace a.out чтобы просмотреть соответствующие системные вызовы(2).

Конечно, прочитайте несколько раз документацию fork(2). и execve(2)

Поскольку оболочка bash является бесплатное программное обеспечение, вы можете изучить его исходный код. Он действительно часто звонит fork!

person Basile Starynkevitch    schedule 10.11.2014
comment
Спасибо! Я собираюсь внести исправления в мою схему и наблюдения. Ваш ответ затронул большинство моих вопросов. Дайте мне немного помариноваться. - person lucidgold; 10.11.2014
comment
Ваша диаграмма симпатична, но она мало что говорит о том, что вы понимаете. - person Basile Starynkevitch; 10.11.2014
comment
Я обновлю его, так как я сказал, что он меня не устраивает. Но я, по крайней мере, хочу, чтобы мой вопрос и ответ на него понравились всем, даже если они не посещали уроки ОС. - person lucidgold; 10.11.2014
comment
Не используйте статическую диаграмму. Попробуйте подумать (мысленно) о фильме. Время имеет значение! - person Basile Starynkevitch; 10.11.2014