Yeni süreçler oluşturmak için neden çatal kullanmamız gerekiyor?


95

Unix’te, ne zaman yeni bir süreç oluşturmak istediğimizde, şu anki süreci uygularız, ana süreçle tamamen aynı olan yeni bir alt süreç oluşturur; daha sonra, ana işlemden gelen tüm verileri yeni işlemle değiştirmek için bir exec sistem çağrısı yaparız.

Neden en başta ana işlemin bir kopyasını oluşturuyoruz ve doğrudan yeni bir işlem oluşturmuyoruz?


Yanıtlar:


61

Kısa cevap forkUnix'tir, çünkü o zaman mevcut sisteme sığması kolaydı ve Berkeley'deki bir önceki sistem çatal kavramını kullandığı için.

Gönderen Unix Zaman paylaşım Sisteminin Evrimi (ilgili metin edilmiştir vurgulanmış ):

Modern formdaki proses kontrolü birkaç gün içerisinde tasarlandı ve uygulandı. Mevcut sisteme ne kadar kolay monte edildiği şaşırtıcı; Aynı zamanda , tasarımın biraz sıradışı özelliklerinden bazılarının tam olarak nasıl mevcut olduğunu görmek kolaydır çünkü var olandaki küçük, kolay kodlanmış değişiklikleri temsil ederler . Bunun iyi bir örneği çatalın ve çalıştırma işlevlerinin ayrılmasıdır. Yeni süreçlerin yaratılması için en yaygın model, sürecin yürütülmesi için bir programın belirlenmesini içerir; Unix'te, çatallı bir işlem, açık bir yürütme gerçekleştirinceye kadar aynı programı üst ile aynı çalıştırmaya devam eder. Fonksiyonların ayrılması kesinlikle Unix'e özgü değildir ve aslında Thompson'la bilinen Berkeley zaman paylaşım sisteminde de vardı.. Yine de, Unix'te var olduğunu varsaymak mantıklı görünüyor; bunun nedeni, çatalı başka bir şey değiştirmeden uygulayabilme kolaylığı . Sistem zaten çok sayıda (yani iki) işlemi ele aldı; bir işlem tablosu vardı ve işlemler ana bellek ile disk arasında değiştirildi. Sadece çatalın ilk uygulaması gerekli

1) Süreç tablosunun genişletilmesi

2) Mevcut işlemi disk takas alanına, mevcut takas IO ilkellerini kullanarak kopyalayan ve işlem tablosunda bazı ayarlamalar yapan bir çatal çağrısı eklenmesi.

Aslında, PDP-7'nin çatal çağrısı, tam 27 satır montaj kodu gerektiriyordu. Tabii ki, işletim sistemindeki ve kullanıcı programlarındaki diğer değişiklikler gerekliydi ve bazıları oldukça ilginç ve beklenmedikdi. Ancak, bir arada çatal yürütme, ancak yürütüldüğü için olmasaydı, çok daha karmaşık olurdu ; işlevi zaten açık IO kullanılarak kabuk tarafından gerçekleştirildi.

O kağıttan beri Unix gelişti. forkardından execartık bir programı çalıştırmak için tek yoldur.

  • vfork , yeni sürecin çataldan hemen sonra bir işlem yapmayı düşündüğü durum için daha verimli bir çatal olarak yaratıldı. Bir vfork yaptıktan sonra, ana ve alt işlemler aynı veri alanını paylaşır ve ana işlem alt işlem bir program yürütene veya çıkana kadar askıya alınır.

  • posix_spawn yeni bir işlem oluşturur ve bir dosyayı tek bir sistem çağrısında yürütür. Arayan kişinin açık dosyalarını seçerek paylaşmanıza ve sinyal konumlarını ve diğer özelliklerini yeni işleme kopyalamanıza izin veren birçok parametre alır.


5
Güzel cevap ama vfork'un artık kullanılmaması gerektiğini de ekleyeceğim. Performans farkı şimdi marjinal ve kullanımı tehlikeli olabilir. Bu SO soru stackoverflow.com/questions/4856255/... bu site Bkz ewontfix.com/7 vfork hakkında ve "Gelişmiş Unix Programlama" sayfa 299
Raphael Ahrens

4
posix_spawn()Kolayca fork()ve satır içi kod kullanılarak yapılabilen çatal-sonrası tekrar doldurma işlerini yapmak için gereken işlemler (veri yapısı ayarı), kullanımı fork()çok daha basit olduğu için zorlayıcı bir argüman yapar .
Jonathan Leffler

34

[Cevabımın bir kısmını buradan tekrarlayacağım .]

Neden sadece sıfırdan yeni bir süreç yaratan bir emir almıyorsunuz? Sadece hemen değiştirilecek olanı kopyalamak saçma ve verimsiz değil mi?

Aslında, bu muhtemelen birkaç nedenden dolayı etkili olmayacaktır:

  1. fork()Çekirdek yazma üzerine bir kopya sistemi kullandığından, "tarafından üretilen" kopya " bir soyutlamadır ; Gerçekten yaratılması gereken tek şey sanal bir hafıza haritası. Kopya hemen derhal çağrılırsa exec(), işlemin etkinliği tarafından değiştirildiyse kopyalanacak verilerin çoğu, işlemin kullanılmasını gerektiren herhangi bir şey yapmadığından aslında hiçbir zaman kopyalanmamalı / oluşturulmamalıdır.

  2. Alt sürecin çeşitli önemli yönleri (örneğin, çevresi) bağlamın karmaşık bir analizine dayanarak ayrı ayrı çoğaltılmamalı veya ayarlanmamalıdır. Çağrılan işlemle aynı olduğu varsayılır ve Bu, aşina olduğumuz oldukça sezgisel bir sistemdir.

# 1'i biraz daha açıklamak gerekirse, "kopyalanan" ancak daha sonra hiçbir zaman erişilemeyen bellek, en azından çoğu durumda hiçbir zaman gerçekten kopyalanmaz. Bu bağlamda bir istisna olabilir , sonra bir süreç çatallı çocuk kendini yerini önce üst süreç çıkmak olsaydı olmak exec(). Diyorum kudretini yeterli boş bellek varsa ebeveynin çok önbelleğe alınabilir, çünkü, ben (OS uygulanmasına bağlı olacaktır) ne ölçüde bu istismar olacağını emin değilim.

Tabii ki, bu yüzeyde boş bir kayrak kullanmaktan daha etkili bir kopya kullanmayı kolaylaştırmaz - "boş kayrak" tam anlamıyla hiçbir şey değildir ve tahsisat içermelidir. Sistem, aynı şekilde kopyaladığı genel bir boş / yeni işlem şablonuna sahip olabilir, 1, ancak daha sonra yazma-kopyalama çatalı ile ilgili hiçbir şey kaydetmez. Yani # 1 sadece "yeni" bir boş işlem kullanmanın daha verimli olmayacağını gösteriyor.

Nokta # 2, çatal kullanmanın neden daha verimli olduğunu açıklıyor. Tamamen farklı bir çalıştırılabilir olsa bile, çocuğun ortamı ebeveyninden miras alınır. Örneğin, ana işlem bir kabuksa ve çocuk bir web tarayıcısıysa, $HOMEikisi için de aynıdır, ancak daha sonra her ikisini de değiştirebildiğinden, bunlar iki ayrı kopya olmalıdır. Çocukta olan orijinal tarafından üretilir fork().

1. Çok fazla anlam ifade etmeyen bir strateji, ama benim açımdan bir işlem yaratmanın, imajını diskten belleğe kopyalamaktan daha fazlasını gerektirdiğidir.


3
Her iki nokta da doğru olsa da, verilen yürütülebilir dosyadan yeni bir işleme ulaşmak yerine neden forking yönteminin seçildiğini de desteklemez.
SkyDan

3
Bunun soruyu cevapladığını düşünüyorum. Çatal kullanılır, çünkü yeni bir sürecin yaratılmasının en etkili yol olduğu durumlarda çatal kullanmanın maliyeti önemsizdir (işlem yaratma maliyetinin% 1'inden daha az). Öte yandan, çatalı önemli ölçüde daha verimli ya da bir API için çok daha basit hale getiren birçok yer var (örneğin dosya işleme gibi). Unix'in verdiği karar sadece bir API'yi destekleyerek, şartnameyi kolaylaştırdı.
Cort Ammon

1
Haklısın @SkyDan, bu bir cevap daha var neden ziyade neden ben yorumlamak hangi anlamında değil, sadece bu en kolay seçenek olduğunu, muhtemelen aynı zamanda olduğunu - Mark Plotnick daha doğrudan cevap hangi en verimli seçim (Dennis Richie'nin teklifine göre: "PDP-7'nin çatal çağrısı tam olarak 27 montaj hattını gerektiriyordu ... böyle bir şey yoktu; işlevi zaten gerçekleştirildi"). Öyleyse bu "neden olmasın" aslında yüzeysel olarak daha basit ve daha verimli göründüğü iki strateji hakkında bir musing , belki de olmadığında (şüpheli kadere tanık olun ...
goldilocks

1
Goldilocks doğru. Dövme ve modifikasyonun sıfırdan yeni bir tane oluşturmaktan daha ucuz olduğu durumlar vardır. En uç örnek, elbette, bir çatal davranışını istediğiniz zaman istediğiniz zamandır. fork()çok hızlı bir şekilde yapabilir (GL'nin dediği gibi, 27 montaj hattının sırasına göre). Diğer bir yöne bakmak, eğer "sıfırdan bir işlem yarat" istiyorsanız, fork()boş bir işlemden başlamaktan çok daha pahalıya mal olacak (27 montaj hattı + dosya tutma işlemlerinin maliyeti). Bu yüzden forkhem çatalı hem de iyi yaratabilirsiniz, oysa createsadece tutabilir.
Cort Ammon

2
Cevabınız, donanım geliştirmelerine atıfta bulundu: sanal bellek, üzerine yazma üzerine. Bundan önce, forkaslında tüm işlem belleğini kopyaladı ve çok pahalıydı.
Barmar

6

Unix'in sadece forkyeni süreçler yaratma fonksiyonunun olmasının sebebinin Unix felsefesinin bir sonucu olduğunu düşünüyorum.

Bir şeyi iyi yapan bir fonksiyon inşa ederler. Bir çocuk süreci yaratır.

Yeni süreçte ne yapılması gerektiği programlayıcıya kalmıştır. exec*İşlevlerden birini kullanabilir ve farklı bir program başlatabilir ya da exec kullanamadı ve aynı programın iki örneğini kullanamadı; bu faydalı olabilir.

Böylece kullanabildiğiniz için daha büyük bir özgürlük elde edersiniz.

  1. exec olmadan çatal *
  2. exec * ile çatal veya
  3. sadece exec * çatal olmadan

ve ayrıca sadece 1970'lerde yapmanız gereken forkve exec*işlev çağrıları ezberlemeniz gerekir .


3
Çatalların nasıl çalıştığını ve nasıl kullanılacağını anlıyorum. Fakat neden aynı şeyi daha az çabayla yapabildiğimde yeni bir süreç oluşturmak isteyeyim? Örneğin, öğretmenim bana, sayının asal olup olmadığını kontrol etmek için argv'a iletilen her sayı için bir işlem oluşturmam gereken bir görev verdi. Ama sonuçta aynı şeyi yapmanın bir yolu değil mi? Sadece bir dizi kullanabilir ve her sayı için bir işlev kullanabilirdim ... Öyleyse neden ana işlemi tüm işlemleri yapmak yerine alt işlemler yaratıyoruz?
user1534664

2
Çatalların nasıl çalıştığını ve nasıl kullanılacağını anladığınızı söylemeye teşebbüs etmek isterim, çünkü bir zamanlar size bir grup işlem yapmak zorunda olduğunuz bir ödev veren bir öğretmeniniz oldu (çalışma zamanında belirtilmiş). onları kontrol et, koordine et ve aralarında iletişim kur. Elbette hiç kimse gerçek hayatta böyle önemsiz bir şey yapmaz. Ancak, kolayca paralel olarak işlenebilecek parçalara ayrıştırılan büyük bir sorununuz varsa (örn. Görüntüdeki kenar algılama), çatallama, aynı anda birden fazla CPU çekirdeği kullanmanızı sağlar.
Scott,

5

Süreç yaratmanın iki felsefesi vardır: kalıtımsal olan çatal ve tartışmalarla yaratma. Unix belli ki çatal kullanıyor. (Örneğin OSE ve VMS, create yöntemini kullanır.) Unix, MANY kalıtımsal özelliklere sahiptir ve daha fazlası düzenli aralıklarla eklenir. Kalıtım yoluyla, bu yeni özellikler mevcut programları değiştirmeden eklenebilir! Argümanlar ile oluştur modelini kullanarak, yeni özellikler eklemek, create çağrısına yeni argümanlar eklemek anlamına gelir. Unix modeli daha basittir.

Aynı zamanda, bir işlemin kendisini birden fazla parçaya bölebildiği, son derece kullanışlı, uygulayıcı olmayan çatal modelini verir. Bu, herhangi bir zaman uyumsuz G / Ç olmadığında hayati öneme sahipti ve bir sistemdeki çoklu CPU'lardan faydalanırken kullanışlıdır. (Önceden iş parçacığı.) Bunu yıllar içinde, son zamanlarda bile çok yaptım. Temelde, birden fazla 'programı' tek bir programda konteynerlere ayırmaya izin veriyor, bu nedenle kesinlikle yolsuzluk veya versiyon uyumsuzluklarına yer yok.

Çatal / yürütme modeli ayrıca belirli bir çocuğun çatal ve yürütme arasında kurulan radikal bir şekilde garip bir çevreyi devralma kabiliyetini de sağlar. Miras alınan dosya tanımlayıcıları, özellikle. (Stdio fd'nin bir uzantısı.) Yaratma modeli, yaratma çağrısının yaratıcıları tarafından öngörülmeyen bir şeyi miras alma olanağı sunmaz.

Bazı sistemler ayrıca, işlemin kendi yerel kod programını yazması için geçerli olan yerel kodun dinamik derlenmesini de destekleyebilir. Başka bir deyişle, kaynak kod / derleyici / bağlayıcı döngüsünden geçmek zorunda kalmadan, disk alanı kaplamak zorunda kalmadan, kendisini anında yazdığı yeni bir program istiyor. (Bunu yapan bir Verilog dil sistemi olduğuna inanıyorum.) Çatal modeli bunu destekliyor, yaratma modeli normalde değil.


Dosya tanımlayıcıları “stdio'nun bir uzantısı” değildir; stdio dosya işaretçileri, dosya tanımlayıcılarının etrafındaki bir sarmalayıcıdır. İlk önce dosya tanımlayıcıları geldi ve bunlar temel Unix I / O tutamaçları. Ancak, aksi takdirde, bu iyi bir nokta.
Scott

2

Fork () işlevi yalnızca baba sürecini kopyalamakla kalmaz, sürecin baba ya da oğul süreci olduğunu belirten bir değer döndürür, aşağıdaki resimde çatal () işlevini bir baba olarak nasıl kullanabileceğinizi açıklar. oğul:

görüntü tanımını buraya girin

İşlem baba çatalı () olduğunda gösterildiği gibi, oğul işlem kimliğini PID döndürürse0

örneğin, istekleri alan bir işleminiz (web sunucusu) varsa ve talepleri her birinde son processbu isteği işlemek için yaratırsanız, burada baba ve oğullarının farklı işleri vardır.

SO, hiçbir işlemin bir işleminin kopyası, çatal () gibi kesin bir şey değil.


5
Doğru olsa da, bu soruyu cevaplamıyor. Farklı bir çalıştırılabilir çalıştırmak istiyorsanız neden işlem oluşturma için çatal gerekli?
SkyDan

1
SkyDan'a katılıyorum - bu soruya cevap vermiyor. posix_spawn , 30 yıl önce ( Posix'in varlığından önce) fork_execve işlevi olarak hayal edilebilecek şeylerin biraz daha iyi bir versiyonudur ; ana sürecin görüntüsünü kopyalamaktan bile çekinmeden (bağımsız değişken listesi, ortam ve işlem öznitelikleri (örn. çalışma dizini)) görüntüyü çalıştırılabilir bir dosyadan başlatan yeni bir işlem yaratan ve Arayan kişiye yeni işlemin PID'si (üst işlem) .
Scott

1
"Ebeveyn" bilgisini bir çocuğa iletmenin başka yolları da vardır. Dönüş değeri tekniği, sadece ilk etapta fork istediğinizi varsayarsanızfork
Cort Ammon

0

G / Ç yönlendirmesi en kolay çataldan sonra ve çalıştırmadan önce uygulanır. Çocuk, onun çocuğu olduğunun farkında olarak, dosya tanımlayıcılarını kapatabilir, yenilerini açabilir, dup () veya dup2 () onları doğru fd numarasına, vb. Bunu yaptıktan sonra ve belki de istenen herhangi bir çevre değişkeni değişikliği (ebeveyni etkilemeyebilir), yeni programı özel ortamda yürütebilir.


Burada yaptığınız tek şey Jim Cathey'in cevabının üçüncü paragrafını biraz daha ayrıntılı olarak tekrarlamak .
Scott

-2

Bence buradaki herkes çatalın nasıl çalıştığını biliyor ama soru şu ki çatal kullanarak ebeveynin tam bir kopyasını oluşturmamız gerekiyor. Cevap ==> İstemci-1 sunucuya erişirken, aynı zamanda ikinci istemci-2 gelirse ve sunucuya erişmek istiyor ancak sunucu yeni gelenlere izin vermiyorsa, sunucuya bir örnek (çatalsız) alın. istemci-2, sunucu istemci-1’e hizmet vermekle meşgul olduğundan, istemci-2 beklemek zorundadır. İstemci-1’e giden tüm hizmetleri tamamladıktan sonra, istemci-2 şimdi sunucuya erişebilir. müşteri-3 geldiğinde, müşteri-3, müşteri-2'nin tüm hizmetlerinin bitinceye kadar beklemesi gerekir. Binlerce istemcinin sunucuya aynı anda erişmesi gereken senaryoyu alın ... sonra tüm istemcilerin bekleyin (sunucu meşgul!).

Bu, sunucunun tam yinelenen kopyasını (yani, çocuğunu) oluşturmak (çatal kullanarak) oluşturmaktan kaçınır; burada her bir çocuk (ebeveyninin, yani sunucusunun tam kopyası), yeni gelen müşteriye adanmıştır, bu nedenle tüm istemciler aynı anda erişir. sunucusu.


Bu nedenle sunucu işlemlerinin tek iş parçacıklı olmaması, aynı anda ele alınabildiği zaman istemci taleplerini arka arkaya ele almaması gerekir - örneğin, ayrı işlemlerde. Ancak, çok iş parçacıklı sunucu modeli, istemcilerden gelen istekleri kabul eden ve müşteri hizmet programını yürütmek için yepyeni bir işlem oluşturan bir dinleyici işlemle kolayca uygulanabilir. Ana işlemi kopyalayan çağrı tarafından sunulan tek avantaj, iki ayrı programa sahip olmanızın gerekmemesidir - ancak ayrı programlara (örneğin ) sahip olmak sistemi daha modüler hale getirebilir. forkinetd
Scott
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.