Neden vfork (), alt süreç oluşturulduktan hemen sonra exec () veya exit () çağırdığında kullanılmalıdır?


11

İşletim Sistemi Kavramları ve APUE diyor

Vfork () ile üst işlem askıya alınır ve alt işlem, üst öğenin adres alanını kullanır. Vfork () yazma üzerine kopyalama özelliğini kullanmadığından, alt işlem üst öğenin adres alanının herhangi bir sayfasını değiştirirse, değiştirilen sayfalar devam ettikten sonra üst tarafından görülebilir. Bu nedenle, alt işlemin üst öğenin adres alanını değiştirmemesini sağlamak için vfork () dikkatle kullanılmalıdır.

vfork (), alt süreç oluşturulduktan hemen sonra exec () veya exit () öğesini çağırdığında kullanılmak üzere tasarlanmıştır.

Son cümleyi nasıl anlayacağım?

Bir çocuk tarafından oluşturulan zaman vfork()çağrıları exec(), gelmez exec()yeni bir program yükleyerek ana işlem adres alanı, değiştirmek?

Bir çocuk tarafından oluşturulan zaman vfork()çağrıları exit(), yok exit()çocuk sonlandırma zaman ebeveyn sürecinin adres alanını değiştirmez?

Linux'u tercih ediyorum.

Teşekkürler.

Yanıtlar:


15

Bir çocuk tarafından oluşturulan zaman vfork()çağrıları exec(), gelmez exec()yeni bir program yükleyerek ana işlem adres alanı, değiştirmek?

Hayır, exec()yeni program için yeni bir adres alanı sağlar; üst adres alanını değiştirmez. Örneğin POSIX'teki işlevlerin ve Linux kılavuzunun tartışmasınaexec bakın .execve()

Vfork () tarafından oluşturulan bir alt işlem exit () öğesini çağırdığında, exit () alt öğeyi sonlandırırken üst işlemin adres alanını değiştirmez mi?

Düz exit()olabilir - çalışan program (kütüphaneleri dahil) tarafından kurulan çıkış kancalarını çalıştırır. vfork()daha kısıtlayıcıdır; Böylece, Linux üzerinde, bu zorunlu kılan kullanımını _exit()hangi gelmez C kütüphanenin temizlik işlevlerini çağırın.

vfork()doğru olması oldukça zor olduğu ortaya çıktı; POSIX standardının geçerli sürümlerinde kaldırılmıştır ve posix_spawn()bunun yerine kullanılmalıdır.

Eğer sürece Ancak, gerçekten ne yaptığınızı biliyorum, sen gerekir değil birini kullanabilirsiniz vfork()veya posix_spawn(); iyi yaşlı fork()ve exec().

Yukarıda bağlanan Linux kılavuz sayfası daha fazla bağlam sağlar:

Bununla birlikte, kötü eski günlerde fork(2) , genellikle hemen sonra bir exec(3)an yapıldığından , genellikle gereksiz yere, arayanın veri alanının tam bir kopyasının yapılmasını gerektirir . Böylece, daha fazla verimlilik için BSD vfork() , ana sürecin adres alanını tam olarak kopyalamayan, ancak bir çağrı execve(2)veya çıkış gerçekleşinceye kadar ebeveynin belleğini ve kontrol iş parçasını ödünç alan sistem çağrısını başlattı . Çocuk kaynaklarını kullanırken ana süreç askıya alındı. Kullanımı vfork()zordu: örneğin, ana süreçteki verileri değiştirmemek, bir kayıtta hangi değişkenlerin tutulduğunu bilmeye bağlıydı.


Teşekkürler. "exec () yeni program için yeni bir adres alanı sağlar;" Bir programı işlemin adres alanına yüklemek normal olarak exec () davranışı mıdır? Normalde veya özellikle vfork () için yeni bir adres alanı oluşturduğu iki bağlantıda bulamadım.
Tim

1
Komik olan vfork () şimdi hemen her şeye karşı kazanıyor. Bir gigabayt yazılabilir belleğiniz olduğunda çataldan () gülünç derecede daha hızlıdır.
Joshua

2
Lütfen insanlara kullanmasını söylemeyin posix_spawn. Bu kullanarak doğru kod yazmak zor belirgin olan posix_spawndüz eski ile daha forkve Denersen, size arasında yapılan gerek birşey yapan dosyanın eylem veya nitelik orada olmamakla tuğla duvar içine çalışabilir forkve exec. Ve vfork benzeri bir verimliliğe sahip olduğu garanti edilmez, bu yüzden insanların çözmek istediği sorunu bile çözmez.
zwol

1
@zwol: Bu gerçekten kötü bir tavsiye. posix_spawnİstediğiniz işlevsellikten yoksun olsa da (bunu C veya cmdline satır içi kabuk komut dosyasında yazılan bir aracı yardımcı program aracılığıyla çözebilirsiniz), istediğinizi elde etmek için yapılan herhangi bir girişim vforktehlikeli tanımlanmamış davranışa neden olur. İçin belirtim vfork, çocuğun daha önce devralması için durumu ayarlamak üzere rasgele işlevlerin çağrılmasına izin vermez execveve bunu yapmaya çalışmak ebeveynin durumunu bozabilir.
R .. GitHub BUZA YARDIMCI DURDUR

1
@Joshua: Modern bir uygulama, çoğu koşulda posix_spawnkabaca aynıdır vfork. Bir farkın olduğu durumlar tam olarak vforkgüvensiz olan durumlar olma eğilimindedir : posix_spawnexec önce çocukta çalışmasını engellemek zorunda kurulu sinyal işleyicileri vardır.
R .. GitHub BUZA YARDIMCI DURDUR

4

Aradığınızda vfork(), yeni bir işlem oluşturulur ve bu yeni işlem, yığının haricinde üst işlemin işlem görüntüsünü ödünç alır. Alt sürece kendi yeni bir yığın yıldız verilir, ancak returnçağrılan işlevden izin verilmez vfork().

Çocuk çalışırken, üst öğenin adres alanını ödünç aldığından üst işlem engellenir.

Ne yaparsanız yapın, yığına erişen her şey yalnızca çocuğun özel yığınını değiştirir. Bununla birlikte, genel verileri değiştirirseniz, bu ortak verileri değiştirir ve böylece üst öğeyi de etkiler.

Global verileri değiştiren şeyler:

  • malloc () veya free () çağrısı

  • stdio kullanma

  • sinyal ayarlarını değiştirme

  • çağrılan işleve yerel olmayan değişkenleri değiştirme vfork().

  • ...

Aradığınızda _exit()(önemli, asla aramayın exit()), çocuk feshedilir ve kontrol ebeveyne geri verilir.

exec*()Ailenin herhangi bir işlevini çağırırsanız , yeni program kodu, yeni veriler ve üst öğeden yığının bir kısmı ile yeni bir adres alanı oluşturulur (aşağıya bakın). Bu hazır olduğunda, çocuk artık adres alanını çocuktan ödünç almaz, ancak kendi adres alanını kullanır.

Adres alanı artık başka bir işlem tarafından kullanılmadığından denetim ana öğeye geri verilir.

Önemli: Linux'ta gerçek bir vfork()uygulama yoktur . Linux , 1988'de SunOS-4.0 tarafından sunulan vfork()Yazma Üzerine Kopyala fork()konseptini temel alarak uygular . Kullanıcıların kullandıklarına inandırabilmeleri için vfork()Linux, paylaşılan verileri ayarlar ve çocuk aramadığında _exit()veya exec*()işlevlerden biri varken ebeveynini askıya alır .

Bu nedenle Linux vfork(), çekirdeğin içindeki bir çocuk için gerçek bir adres alanı tanımlaması gerekmediği gerçeğinden faydalanmaz . Bu vfork(), daha hızlı olmayan bir sonuç verir fork(). Bir gerçek uygulayan sistemlerde vfork(), tipik olarak 3 kat daha hızlıdır fork()ve kullanılan mermilerin performansını etkiler vfork()- ksh93, son Bourne Shellve csh.

Aradığınızda asla nedeni exit()dan vfork()ed çocuğun olmasıdır exit()basması zaman unflushed veri çağırmadan önce olduğu durumda stdio vfork(). Bu garip sonuçlara neden olabilir.

BTW: posix_spawn()üstüne uygulanır vfork(), bu yüzden vfork()işletim sisteminden kaldırılmaz. Linux kullanmayan söz edilmiştir vfork()için posix_spawn().

Yığın için, birkaç doküman var, Solaris man sayfasının söylediği şey:

 The vfork() and vforkx() functions can normally be used  the
 same  way  as  fork() and forkx(), respectively. The calling
 procedure, however, should not return while running  in  the
 child's  context,  since the eventual return from vfork() or
 vforkx() in the parent would be to a  stack  frame  that  no
 longer  exists. 

Böylece uygulama istediği her şeyi yapabilir. Solaris uygulaması, işlev çağrısının yığın çerçevesi için paylaşılan bellek kullanır vfork(). Hiçbir uygulama, üst öğeden yığının eski kısımlarına erişim izni vermez.


4
Ne GNU C kütüphanesi ne de musl C kütüphanesi posix_spawn()Linux'un üstüne uygulanmaz vfork(). Her ikisi de üstüne uygular __clone().
JdeBP

1
@JdeBP: vfork()Sadece aramaları biliyorsun clone()değil mi? Kelimenin tam anlamıyla çekirdekte bir astar.
Joshua

1
"Önemli: Linux'ta gerçek bir vfork () uygulaması yoktur." <- Bu doğru değil ve en az on yıldır doğru değil. Kabuk ölçütünüz Linux arasında vforkve forkLinux'ta herhangi bir performans farkı gözlemlemiyorsa , yanlış bir şey yapıyor demektir.
zwol

1
"Önemli: Linux'ta gerçek bir vfork () uygulaması yoktur" ile başlayan bu cevabın ikinci yarısı çoğunlukla ya da tamamen yanlıştır.
R .. GitHub BUZA YARDIMCI DURDUR

1
Lütfen doğrulamadan hak talebinde bulunmayın. Mevcut Bourne Kabuğu vfork desteği ile ve vfork desteği olmadan derlenebilir, bu nedenle Linux'tan hata ayıklama özelliklerinin güvenilir sonuçlar veremediğine inansanız bile, bir yapılandırma çağrısının yürütme sürelerini kabuktaki vfork ile karşılaştırabilirsiniz. 800 testli bir yapılandırma betiği kullanıyorum. Solaris'te vfork kullanan Bourne Shell, çatal kasasına kıyasla toplamda% 30 daha az sistem işlemci süresine ihtiyaç duyuyor. Linux'ta aynı test% 10'dan daha az sistem işlemci süresi ile sonuçlanır. Solaris'de birçok derleyici çağrısı olduğu için 3x değildir.
şevkle
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.