защо fork() връща всички възможни резултати в тази комбинация?

Въпрос:

Имам нужда от пояснение/помощ относно моето разбиране за изходите на fork(). Знам как да програмирам по-подробен и по-голям код в c с fork() и да използвам други концепции като pipe, ipc, threads(posix). Но моето разбиране с прогнозиране на изхода за връщане е лошо, поради което се опитвам да разбера това. Вярвам, че моят случай 1 е правилен, но другите ми случаи са двусмислени или подобни на този, защото не съм съвсем стабилен с изхода на fork() .

Познанията ми с програмния изход са прилични, разбирам основни алгоритми, които съдържат for-loop, while-loop, if/else, структури от данни, рекурсивни изходи.

Въпреки това липсват ми познания за това как програмите, използващи fork() точно извеждат и как комбинациите родител/дете обработват точно както е посочено по-долу.

Моят подход:

Първоначално имаме родителски процес, изпълняващ p0, след което pid разклонява дъщерен процес.

Така че всички възможни изходи винаги ще съдържат 0, тъй като num=0 първоначално и преди първия оператор prinf() num не е зададен на друго число.

Вярвам, че времето за изпълнение на родителския и дъщерния процес е произволно, защото може да излезе във всякакъв ред.

случай 1: p0 отпечатва 02, защото може да има случай, когато pid е родител. След това раздвоеният дъщерен процес p1 отпечатва 01. Крайният отговор ще бъде 0201

случай 2: p0 отпечатва 01, защото може да има случай, при който pid е дете (дали е дете на основния процес от ядрото?). Тогава разклоненото дете p1 е родител, така че отпечатва 0102. Крайният отговор ще бъде 0102

случай 3: p0 отпечатва 00, тъй като pid не е дете или родител. Тогава раздвоеното дете p1 отпечатва 12, защото е дете и родител едновременно. Крайният отговор ще бъде 0012.

случай 4: p0 отпечатва 00, тъй като не е родител или дете. Тогава раздвоеният дъщерен процес p1 отпечатва 21, защото може да бъде родител и дете едновременно. Крайният отговор ще бъде 0021.

Код:

#include <stdio.h>
int num = 0 ;
int main(int argc, char *argv[])
{
  int pid ;
  pid = fork() ;

  printf("%d",num) ;

  if (pid == 0) {
    num = 1;
  } else if (pid > 0) {
    num = 2 ;
  }
  printf("%d",num) ;
}

Отговор: 0102 или 0012 или 0201 или 0021


person geforce    schedule 21.02.2015    source източник
comment
Нямате контрол върху това кога всеки от двата процеса ще се изпълнява или в какъв ред. Ако искате процесите да работят в определен ред, трябва да използвате някакъв вид междупроцесна синхронизация.   -  person Some programmer dude    schedule 21.02.2015
comment
родителят и детето се състезават по този printf до stdout. Няма нищо друго за това.   -  person Red Alert    schedule 21.02.2015
comment
Да, но това, което се опитвам да разбера, е как се намира моделът на всички възможни изходи, защото това е, което не разбирам, защото мога произволно да отпечатам числа като 0120, но то не е включено в „отговорите“.   -  person geforce    schedule 21.02.2015
comment
Прочетете Разширено Linux програмиране. Има няколко глави, обясняващи fork и как да го използвате и кога.   -  person Basile Starynkevitch    schedule 21.02.2015
comment
C е, без да се вземат предвид цикли и подобни, почти последователен. Изявленията се изпълняват отгоре надолу, в реда, който сте програмирали. Така че, ако кодът трябва да отпечата числото 0 преди 1 или 2, тогава числото 0 никога няма да бъде отпечатано, след като отпечатате 1 или 2. Това означава, че случаят 0120 е невъзможен за получаване.   -  person Some programmer dude    schedule 21.02.2015


Отговори (2)


Предполагам, че го усложнявате прекалено много. Това, което се случва след fork(), е, че имате два екземпляра (баща и син), които се изпълняват, като всеки от тях изпълнява две изходни операции.

Двата екземпляра са независими и не знаят нищо един за друг, така че единият няма да чака другия да завърши и имате така нареченото състезателно състояние. Единствената гаранция е, че всеки процес ще изведе първо 0, след това 1 (или 2), защото това е редът на операциите във всеки от тях. Но не можете да кажете как четирите изходни операции ще бъдат преплетени.

person Stefano Sanfilippo    schedule 21.02.2015
comment
дали 0120 е възможен изход? - person geforce; 21.02.2015
comment
Не, защото трябва да запазите правилния ред за всеки екземпляр: първо 0, след това 1 или 2. 0120 можеше да бъде 01 и 20 или 02 и 10, но и двамата не зачитат това. - person Stefano Sanfilippo; 21.02.2015
comment
Когато казвате, че първите изходи трябва да са 0 и след това 1 или 2. Това означава ли, че позиция 0 е 0, след това позиция 1 е 1 или 2? Защото какво, ако позиция 1 е 0 означава ли това, че fork() е неуспешен? - person geforce; 21.02.2015
comment
Не, 0012 е добре. Представете си, че двата екземпляра се изпълняват в отделни прозорци: единият ще изведе 01, а другият 02. нали Сега опитайте да преплитате двата изхода: 0102, 0012 са добре, но 0120 не е, защото няма 0 след 1 или 2 или 0 в отделните изходи. - person Stefano Sanfilippo; 21.02.2015
comment
Започвам да разбирам, че родителският процес винаги ще отпечатва 02, а дъщерният процес винаги ще отпечатва 01, така че комбинациите от изход наистина идват основно от преплитане? - person geforce; 21.02.2015
comment
Да точно. Нещо повече, ако сте отпечатали повече от един знак на printf, изходите биха могли дори да бъдат подредени на ниво символ, така че ако един процес отпечата HELLO WORLD, а другият foo bar baz, можете да получите HELfoo LObarW bazORLD като изход, стига редът на двата независими изходи не се променя. - person Stefano Sanfilippo; 21.02.2015

Нека наречем родителския процес A и дъщерния B. A винаги ще отпечата 0, последвано от 2. B винаги ще отпечата 0, последвано от 1. Времето на A по отношение на B е неопределено. Изходът от A може да се отпечата преди, подреден или след изхода от B.

Всъщност има шест възможни резултата, както е показано по-долу. Въпреки това ще видите само четири различни изходни модела, защото не можете да разберете дали A или B е отпечатано първо, когато изходът започва с 00.

AABB
0201

ABAB
0021

BAAB
0021

ABBA
0012

BABA
0012

BBAA
0102
person user3386109    schedule 21.02.2015
comment
Това има много смисъл, благодаря, че го изяснихте. Доколкото разбирам, ще се опитам да проуча това и да разбера повече, за да мога да отговоря по-късно, защото току-що разбрах, че това основно зависи от преплитането и времето - person geforce; 21.02.2015
comment
Ще прегледам този резултат, който показахте, и ако имам въпроси, ще оставя коментари - person geforce; 21.02.2015
comment
Така че, когато AA или BB се появят в модела, това означава, че няма грешки или преплитане, но когато се появи AB, BA, това означава, че има неизправност/грешка и се получава преплитане? - person geforce; 22.02.2015
comment
@geforce Процесите A и B работят независимо, но споделят едно изходно устройство. На многоядрен процесор A и B ще работят едновременно и ще се състезават за генериране на изход. Ако A спечели, ще видите AABB. Ако B спечели, тогава BBAA. Понякога времето е толкова близко, че изходите се преплитат и получавате нещо като ABAB. При едноядрен процесор операционната система ще превключва между A и B на редовни интервали. Така че A може да изведе 0 и ОС да превключи на B, което извежда 0 1, и след това ОС да превключи обратно на A, което води до ABBA. Няма повреди/грешки, това е просто многозадачност. - person user3386109; 22.02.2015