Bir işlem çıktığında arabellek otomatik olarak diske temizlenir mi?


21

Bir komutun çıktısını bir dosyaya yönlendirdiğimde (örneğin, echo Hello > file) komutun çıkmasından hemen sonra böyle bir dosyaya sahip olacağı garanti edilir mi? Veya komut çıkışı ile dosyaya yazılan veriler arasında hala çok küçük bir pencere var mı? Komut çıktıktan hemen sonra dosyayı okumak istiyorum, ancak boş bir dosya okumak istemiyorum.


1
Muhtemelen hemen komutu çalıştırır, ancak zamanın miktarı aslında dosya, yazma açmaya alır ve yakın hız ve vb sabit diskinizde herhangi çalışan programların türüne bağlı olacaktır
freginold

Verilen örnek açısından “süreç” nedir? Are echove >değil ayrı (kısa ömürlü) işlemleri? Ve daha echoönce kalan çıktı nerede >gerçekleştiriliyor?
oɔɯǝɹ

1
@ oɔɯǝɹ >kabuk yönlendirmedir. Program, adlandırılmış dosyayı yazmak için açmış ve kabuğun yaptığı tam olarak stdout ile değiştirilmişse aynıdır.
Dan D.,

7
Ben sana vermek için OS sorumluluğu olduğunu düşünüyorum fileiçeren Helloolursa olsun kızardı olup olmadığına ait.
Salman A

1
Program makine A'da çalışıyorsa ve makine B'de, makine A dosya sistemi ağ üzerinden monte edilmişse, o zaman ağ dosya sistemi türüne ve takma ayarlarına bağlı olarak boş bir dosyayı okuyabilirsiniz. Bu nedenle, bu bağ için önbelleğe almayı devre dışı bırakmak isteyebilirsiniz.
puanlar

Yanıtlar:


21

İlgili çok sayıda tampon / önbellek katmanı vardır.

  1. CPU önbelleği.

    Veriler bayt tarafından bir araya getirilir ve CPU önbelleğinde saklanır. CPU önbelleği doluysa ve bir süredir veriye erişilmemişse, verilerimizi içeren blok ana belleğe yazılabilir. Bunlar, çoğu, uygulama programcılarından gizlenir.

  2. İşlem içi tamponlar.

    Verilerin toplandığı süreçte bir miktar bellek ayrılmıştır, bu nedenle işletim sistemine mümkün olduğunca az talep yapmamız gerekir, çünkü bu nispeten pahalıdır. İşlem, verileri tekrar CPU önbellekleri tarafından desteklenebilen bu arabelleklere kopyalar, bu nedenle verilerin ana belleğe kopyalanması garantisi yoktur. Uygulamanın bu tamponları açıkça yıkaması gerekir, örneğin fclose (3) veya fsync (3). Exit (3) işlevi, işlem sonlandırılmadan önce de bunu yapar, ancak _exit (2) işlevi çalışmaz , bu nedenle bu sayfada sadece ne olduğunu biliyorsanız bu işlevi çağırmak için el ile sayfasında büyük bir uyarı vardır. yapıyor.

  3. Çekirdek tamponları

    İşletim sistemi daha sonra disklere göndermesi gereken istek sayısını en aza indirmek için kendi önbelleğini korur. Bu önbellek özellikle bir işleme ait değildir, bu nedenle oradaki veriler zaten bitmiş olan işlemlere ait olabilir ve tüm erişimler buradan geçtiği için, bir sonraki program buraya ulaşmışsa verileri görecektir. Çekirdek bu zamanı, zamanı geldiğinde veya açıkça istendiğinde disklere yazacaktır.

  4. Sürücü önbelleği

    Disk kendileri de erişimi hızlandırmak için bir önbellek tutuyorlar. Bunlar oldukça hızlı bir şekilde yazılmıştır ve kalan verileri önbelleklere yazıp komutun tamamlandığını bildirmek için bir işletim sistemi vardır, işletim sisteminin kapatmadan önce hiçbir veri yazılıp bırakılmadığından emin olmak için kullanılır.

Başvurunuz için, verilerin çekirdek arabelleklerine kaydedilmesi yeterlidir (gerçek veriler bu noktada hala CPU önbelleklerinde bulunabilir ve ana belleğe yazılmamış olabilir): "eko" işlemi sona erer. işlem içi arabelleklerin temizlenmiş olması ve verilerin işletim sistemine teslim edilmesi gerektiği ve yeni bir işleme başladığınızda, işletim sisteminin sorulduğunda geri aynı verileri vereceği garanti edilir.


7
CPU önbelleğe almanın benim için önemli olmadığı düşünülüyor. Bu burada gereksiz bir detay seviyesidir. Bir hard disk tablasındaki bir bit veya ssd bellekteki bir kısmı temsil eden bir miktar fiziksel miktar değiştirilinceye kadar değiştirilerek değiştirilir.
mvw

3
Gerçekten de, CPU önbelleği oldukça diktir.
Simon Richter

2
Ve daha da önemlisi, CPU önbelleği çekirdekler arasında tutarlı, bu yüzden tamamen resim dışında. X86'da bile, DMA ile uyumludur (ve x86'nın toplam siparişi hafıza siparişi modu vardır), bu nedenle hafızayı okuyabilen herhangi bir şey, genel olarak hafıza işlemleri sırasındaki bu adrese kaydedilen verileri görecektir. (Bir CPU çekirdeği, mağaza kuyruğundan mağazanın iletilmesi nedeniyle global olarak görünür hale gelmeden önce bile kendi mağazalarını görecektir). Önbellek uyumlu DMA'sı olmayan x86 olmayan platformlarda, Linux çekirdeği, DMA'dan önce bu adreslere önbelleğin temizlenmesini sağlar.
Peter Cordes

1
“Bunlar, çoğu, uygulama programcılarından gizlendi.” Neden "çoğunlukla"? Katıştırılmış bir geliştiriciyim ve önyükleme sırasında (yani "uygulama" değil) CPU önbelleğini tamamen görmezden geliyorum. Herhangi bir uygulama geliştiricisinin CPU önbelleğinin etkilerinden etkilenebileceğini sanmıyorum.
Sam

1
@Sam önbelleği, spekülatif uygulamalarla birlikte özlüyor / vurur, okuma erişim kısıtlamalarını atlamak için bazı CPU'larda kullanılabilir. Belki de cevabı kastettiği budur?
John Dvorak

22

Uygulamanın hiçbir iç önbelleği yoksa, değişiklikler hemen dosyaya yazılır. Örnek için aynı. Dosya, bellekte derhal güncellenecek olan mantıksal bir varlıktır. Dosyadaki sonraki işlemler program tarafından yapılan değişiklikleri görecektir.

Ancak , bu değişikliğin fiziksel diske yazıldığı anlamına gelmez. Değişiklikler OS dosya sistemi önbelleklerinde veya donanım önbelleklerinde kalıcı olabilir. Dosya sistemi arabelleğini temizlemek için synckomutu kullanın.

Komut çıktıktan hemen sonra dosyayı okumak istiyorum, ancak boş bir dosya okumak istemiyorum.

Burada pratik problemlerle karşılaşmamalısın.


1
“Uygulamanın hiçbir iç önbelleği yoksa” - bu çok büyük bir “eğer”: G / Ç kitaplığı uygulamalarının büyük çoğunluğu varsayılan olarak tampon stdout kullanır. Bununla birlikte, örneğin, C standardı stdout arabelleğinin çıkışta yıkanmasını zorunlu kılar (ancak exiten azından dolaylı olarak çağrılmadıysa potansiyel olarak değil ). Diğer kütüphaneler / diller (örneğin, Java!) Daha az garanti verir.
Konrad Rudolph

Ya sadece ilkel yönlendirme (yani benim sorumla emir) ile sınırlandırırsa? İç önbellekleri yok, değil mi?
Eric

@Eric Hayır, iyi olmalısın.
53'te

10
Bu cevabı alır mıyım emin değilim. Soru “süreç sona erdiğinde” ile ilgilidir. Dahili yazma önbelleklerine sahip her uygulama, daha önce gerçekleşmemişse, işlem çıkışında onları diske aktaracaktır. IOW, bu önbellekler burada önemli değil.
MSalters

2
Dahası, bir dahili tampon çıkışta temizlenir veya varlığından kaybolur, değil mi? Bu nedenle, dahili arabellekler temizlenmese bile, ne kadar beklenirse bekletilsin, içerik gözlemlenemez.
WorldSEnder

21

Bir işlem çıktığında arabellek otomatik olarak diske temizlenir mi?

Genel olarak cevap hayır .

Komuta bağlı. Diğer cevapların söylediği gibi, eğer komut verileri dahili olarak tamponlamazsa, komut sona erdiğinde tüm veriler mevcut olacaktır.

Ancak, tümü olmasa da çoğu, standart G / Ç kütüphaneleri varsayılan olarak arabellek stdout yapar (bir dereceye kadar) ve uygulama kapandığında arabelleklerin otomatik olarak yıkanması hakkında farklı garantiler verir.

C normal bir çıkışın tamponları temizleyeceğini garanti eder . “Normal çıkış” exit, açıkça veya geri dönerek denilen anlamına gelir main. Bununla birlikte, anormal çıkış bu çağrıyı atlayabilir (ve bu nedenle arızasız tamponları geride bırakır).

İşte basit bir örnek:

#include <signal.h>
#include <stdio.h>

int main() {
    printf("test");
    raise(SIGABRT);
}

Eğer bu derlemek ve çalıştırmak için, testolacak değil mutlaka Stdout'a yazılabilir.

Diğer programlama dilleri daha da azı garantisi verecek: Java, örneğin, does not programı sona ermesiyle otomatik floş . Çıktı tamponu sonlandırılmamış bir çizgi içeriyorsa, System.out.flush()açıkça belirtilmediği sürece kaybolabilir .

Bununla birlikte, sorunuzun gövdesi biraz farklı bir şey sorar: veriler dosyaya hiç gelirse , komut sona erdikten hemen sonra yapmalıdır (diğer cevaplarda açıklanan uyarılara tabi).


7
Ayrıca bir komut satırı aracı bir dosyaya ve bir hata ayıklama günlüğü gibi stdout ya da stderr'ye yazarken ve kullanıcı daha az çıkmak için 'q' yazıp bir başa ya da daha az bir boru yapdığında anormal bir çıkış gördüm. Komut satırı aracı SIGPIPE'i işlemezse, disk dosyası her zaman tam olarak temizlenmez.
Zan Lynx,

+1, ancak " komut sona erdikten hemen sonra yapılmalı " tam olarak doğru değil: herhangi bir write()veya pwrite()sistem çağrısı işlem sona ermeden önce gerçekleşecek ve bu durumda dosya değişiklikleri görünür hale gelecektir. Yani son dosya değişim kesinlikle önce en geç hemen öncesinde, işlem sonlandırma. Bir mmap(MAP_SHARED)dosyada bile, gerçekleşecek tüm dosya değişikliklerinden önce, işlemin sonlandırıldığını gözlemlemenin hiçbir yolu olmadığını düşünüyorum.
Peter Cordes

9

Bence henüz hiçbir soru bu konuyu yeterince ele almıyor:

Komut çıktıktan hemen sonra dosyayı okumak istiyorum, ancak boş bir dosya okumak istemiyorum.

Diğer cevapların açıkladığı gibi, iyi davranış gösteren bir program, işlem normal şekilde sona ermeden önce iç dosya tamponlarını temizler . Daha sonra, veriler kalıcı depolamaya yazılmadan önce hala çekirdek veya donanım tamponlarında kalabilir. Bununla birlikte , Linux'un dosya sistemi anlambilimi, tüm işlemlerin dosyaların içeriğini iç arabellekleri 1 dahil olmak üzere çekirdekle aynı şekilde görmesini garanti eder .

Bu genellikle dosya nesnesi başına en fazla bir çekirdek içi arabellek olması ve bu arabellek üzerinden geçmek için tüm dosya erişimini gerektirmesi ile gerçekleştirilir.

  • Bir işlem bir dosyayı okursa, istenen dosya kısmı şu anda arabellekte ise çekirdek, işleme arabellek içeriğini sunacaktır; değilse, çekirdek, verileri temeldeki depolama ortamından alır ve arabellek içine yerleştirir, ardından önceki adıma geri döner.

  • Bir işlem bir dosyaya yazarsa, veriler önce o dosyanın çekirdek içi tamponunun içine yerleştirilir. Sonunda tampon içeriği depoya temizlenir. Bu arada okuma erişimi aynı tampondan (yukarı bakın) karşılanır.


1 En azından normal dosyalar, dizinler ve sembolik bağlantılar için. FIFO'lar ve soketler farklı bir konudur çünkü içerikleri hiçbir zaman kalıcı olarak saklanmaz. İçeriği kimin sorduğuna bağlı olan bazı özel dosyalar vardır; örnekler, procfs ve sysfs'teki dosyalardır (bunun /proc/selfsembolik bağlantıyı okuyan işlemin işlem kimliğine sembolik bir bağlantı olduğunu düşünün ).


2
Açıkçası, bunu garanti eden Linux'un dosya sistemi anlambilimi değil, bunu yapan POSIX anlambilimidir. Özellikle, BSD, macOS ve hatta Windows ile aynı şekilde davranır (bu, Windows'un POSIX anlambilimini takip ettiği birkaç durumdan biri olmasına rağmen). Bu aynı zamanda hiç kimsenin mmap()ve O_DIRECT ile garip şeyler yapmadığını varsayar ; bu da disk ile sayfa önbelleği arasında eşzamanlı olmayan şeylerin ortaya çıkmasına neden olabilir (ancak bu işlemin gerçekleştiği anı çözecektir).
Austin Hemmelgarn

2
@AustinHemmelgarn: Kesinlikle Linux akılda Unix (Sistem V) uygulamaları desteği ile tasarlanmış ve daha sonra da Sistem V'de birçok kavram üsleri POSIX desteklemeye yapıldıktan sonra ikimiz de haklısın konuşan
David Foerster

5

Komutunuzun C çalışma zamanı kütüphanesini kullanan bir program tarafından yürütüldüğünü varsayarsak, bir noktada fcloseaçık dosyayı kapatması için çağırması gerekir .

fcloseC fonksiyonunun man sayfası şöyle diyor:

NOTLAR fclose () öğesinin yalnızca C kütüphanesi tarafından sağlanan kullanıcı alanı tamponlarını temizlediğini unutmayın. Verilerin fiziksel olarak diskte depolandığından emin olmak için, çekirdek tamponlarının da örneğin senk (2) veya fsync (2) ile yıkanması gerekir.

ve man sayfası için fflushaynı nota. İçin man sayfa closediyor ki:

Başarılı bir kapatma, çekirdek savunucularının yazdığı gibi verilerin başarıyla diske kaydedildiğini garanti etmez. Bir dosya sisteminin akış kapalıyken arabellekleri temizlemesi yaygın değildir. Verilerin fiziksel olarak saklandığından emin olmanız gerekiyorsa, fsync (2) kullanın. (Bu noktada disk donanımına bağlı olacaktır.)

Sürücüyle senkronize edilmese bile verilerin diğer işlemler için mevcut olduğunu unutmayın. Belki bu zaten sizin için yeterince iyi.

Şüpheniz varsa, bir test yazın.


2
C olsun ya da olmasın, her şey close()bir dosyanın tanımlayıcısını kapatmak için sistem çağrısı kullanır / kullanmalıdır .
Attie

@Attie: Sen do not ihtiyaç için close(hatalarını kontrol yok hacky programlarda) çıkmadan önce dosyaları; Çekirdek onları temizler close, işleminiz bittikten sonra sizi etkin bir şekilde arar. fcloseHerhangi bir tamponlanmış stdio akışına ihtiyacınız var , ya da exit(3)doğrudan çıkış sistemi çağrısının aksine, libc'in bunu sizin için yapmasına izin verin .
Peter Cordes

Şüpheniz varsa, bir test yazın. Bu, yarış koşullarını tespit etmek için kötü bir tavsiyedir. Tek bir donanım parçası üzerinde çalışan bir çekirdeği test etmek, yarışın bu sistem üzerinde yaptığınız test koşullarında veya bu durumun tespit edilemeyecek kadar zor olduğu durumlarda gerçekleşemeyeceğini söyleyebilir. Ama bu davranış olup olmadığını söyleyemem sözde tüm dosya sistemleri, çekirdekleri arasında güvenli olması için ve tüm donanım (örneğin PowerPC). yani, bağlı olduğunuz garantinin bir uygulama detayı mı yoksa kasıtlı geleceğe dönük bir garanti mi olduğunu söyleyemezsiniz! (Bu durumda öyle.)
Peter Cordes

Bu duruma bağlıdır. Bazı insanlar onun kabuk betiğini çalıştırmaya çalışıyor bu tavsiye size yardımcı olabilir. Daha gelişmiş ancak daha az olası ortamlar için genel bir çözüm olarak tasarlanmamıştır, örneğin bir işletim sistemi çekirdeğinde çalışan bir yazılım mühendisi, bazılarının Intel'in mikro kod güncellemesinde çalışan bir halk mühendisi ya da ISS için bazı sistemler üzerinde çalışan bazı kişiler.
mvw

3

Bir komutun çıktısını bir dosyaya yönlendirdiğimde (örneğin, echo Hello > file) komutun çıkmasından hemen sonra böyle bir dosyaya sahip olacağı garanti edilir mi?

Evet. Kabuk çıktı dosyasını açar ve echodoğrudan buna çıktı verir. Komut çıktıktan sonra yapılır.

Yoksa komut çıkışı ile dosyaya yazılan veriler arasında hala çok küçük bir pencere var mı?

Verilerin zaten medyada olup olmadığı, sadece bir donanım arızası olması durumunda önemli olan bir konu veya monte edilmiş dosya sistemini atlayarak, bazı adli yazılımlarla canlı bölümü inceliyorsunuz.

Komut çıktıktan hemen sonra dosyayı okumak istiyorum, ancak boş bir dosya okumak istemiyorum.

Endişelenmeyin, çekirdek, ne sıklıkta açıldığından bağımsız olarak dosyanın yalnızca bir görünümünü tutar.


"çekirdek, dosyanın yalnızca bir görünümünü tutar": için tam olarak doğru değil mmap(MAP_SHARED): mmaped bölgesine depolanan dosyalar, dosya okumalarıyla tutarlı değil (bu iş parçacığı veya diğer işlemler). Bu yüzden msync(2)var. En azından adam sayfalarının uyardığı şey bu; Uygulamaya bağlı olarak, Linux aslında sayfa sayfalarından fiziksel sayfaları eşleştirebilir; bu durumda temelde tutarlı olduğunu tahmin ediyorum (modulo hafıza sıralaması). Neyse, her şey daha önce oldu _exit(2).
Peter Cordes

2

Genel bir kural olarak, çekirdeğe ait tüm veriler çekirdek tarafından korunur ve temizlenir. Bu veriler, gibi bir sistem çağrısı tarafından çekirdek belleğine aktarılan verileri içerir write(2).

Başvurunuz (örneğin C kütüphanesi) gerçekleştirdiği üzerinde tamponlama Ancak, üst bunun ardından çekirdek besbelli garanti etmez dolayısıyla hiçbir fikri vardır ve onun temizlik.

Dahası, temizlik için herhangi bir zamanlama garantisi olduğuna inanmıyorum - genel olarak “en iyi çaba” (okuma: “s saniye olduğunda”) esasına göre yapılır.


Temizleme işleminin gerçekleşmesi waitpid()durumunda, üst işlemin geri dönmesinden önce temizleme / tampon temizleme işlemlerinin gerçekleşeceğine dair bir garanti vardır . yani, diğer işlemler, bu işlem tarafından yapılan herhangi bir dosya değişikliğinden önce gerçekleşen işlem sonlandırmasını doğrudan gözlemleyemez. (NFS önbelleğe alma ana bilgisayarlar arasında tam olarak tutarlı olmadığı için NFS dosya zaman damgaları aracılığıyla dolaylı gözlemleri dışlamak için "doğrudan" dedim.)
Peter Cordes 10

@PeterCordes: Sanırım "sürdürme" yerine "temizlik" derken ne demek istediğine bağlı. Bana göre "korumak", "bahsettiğiniz garantiye sahip olan" tutarlı bir görünüm sağlamaktır "ve" temizleme ", zamanlama garantisine sahip olmadığına inandığım" diske aynı hizada "dır.
Mehrdad

Anladığım kadarıyla, soruyu okuduktan sonra ne görecekleri ile ilgisi olmayan "diske temizlendi" bölümünü yanıtlıyorsunuz. "kirli önbellek / tampon belleği temizle" anlamında "temizle". Doğru, hiçbir zamanlama garanti kullanmak sürece fsync/ fdatasyncLinux üzerinde tampon geri yazma sonra başlayacaktır rağmen /proc/sys/vm/dirty_writeback_centisecs(diğer I / O trafik gecikmelidir değilse) saniyenin yüzde ve bu procfs dizinde çeşitli diğer tunables da da etkiler (örn nasıl Herhangi bir geri yazma yapmadan önce tamponların büyümesi için büyük).
Peter Cordes

2

Yoksa komut çıkışı ile dosyaya yazılan veriler arasında hala çok küçük bir pencere var mı?

Hayır yok.

Komut çıktıktan hemen sonra dosyayı okumak istiyorum, ancak boş bir dosya okumak istemiyorum.

Dosyanın son içeriğini komut çıktıktan hemen sonra okuyabilirsiniz, bunun yerine boş dosyayı asla okumazsınız. (C ve C ++ 'da, programın çıkmasını beklemek için wait , waitpid , wait3 veya wait4 sistem çağrılarını kullanın ve yalnızca dosyayı okuyun. Bir kabuk, başka bir programlama dili veya bir kütüphane kullanıyorsanız (örn. C kütüphanesi) çağrı sistemi veya Java Süreci sınıfı), muhtemelen bu sistem çağrılarından birini zaten kullanmıştır.)

Diğer cevapların ve yorumların da belirttiği gibi, program dahili çıkış tamponlarını temizlemeden çıkmışsa programdan çıktıktan sonra boş bir dosyayı okumayı bırakabilirsiniz (örn. _Exit , iptal etme veya ölümcül bir sinyal alma veya normal bir şekilde çıkan bir Java programı). Ancak bu noktada bu konuda yapabileceğiniz hiçbir şey yoktur: temizlenmiş veriler sonsuza dek kaybolur, ek bekleme onu kurtarmaz.


0

Evet

Başka gereksiz bir cevap eklediğim için özür dilerim, ancak çoğu sorunun başlığının kırmızı ringalarına odaklanmış görünüyor. Ama söyleyebileceğim kadarıyla, soru hiç tamponlama ile ilgili değil, fakat bu:

Bir komutun çıktısını bir dosyaya yönlendirdiğimde (örneğin, echo Hello> dosyası) bu dosyanın komuttan çıktıktan hemen sonra böyle bir veriye sahip olması garanti edilir mi?

Evet, koşulsuzca. Tarif ettiğiniz ">" ve "|" ve "<", Unix ve Linux dünyasının dayandığı boruya dayalı işleme modelidir. Her Linux kurulumunda bu davranışa bağlı olarak tamamen binlerce komut dosyası olmasa bile yüzlerce tane bulacaksınız.

Tasarım başına istediğiniz gibi çalışır ve bir yarış koşulunun en ufak bir şansı olsa bile, muhtemelen on yıl önce düzeltilmiş olurdu.


Bu maalesef gereksiz. Yanıtların yalnızca birkaçı çoğunlukla geçici olmayan depolamaya veri aktarmanın kırmızı ringa odaklanmasına odaklanmaktadır. Açık bir açıklama için @ pts'nin cevabına ve diğer birkaç tanesine bakınız : dosya değişikliği çıkıştan önce olur veya hiç olmaz.
Peter Cordes
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.