Yeniden giriş (bilgi işlem) - Reentrancy (computing)
Olarak işlem , bir bilgisayar programı ya da bir alt yordam çağrılır evresel birden çağrıların güvenli bir şekilde birden fazla işlemci üzerinde eşzamanlı olarak çalışabilir halinde ya da bir evresel prosedür yürütme ortasında kesilebilir ve daha sonra güvenli bir şekilde yeniden çağrılabilir tek bir işlemci sistemi üzerinde (" yeniden girildi") önceki çağrılar yürütmeyi tamamlamadan önce. Kesinti , yeni çağrıların yalnızca dahili çağrıdan kaynaklanabileceği özyinelemeden farklı olarak, atlama veya çağrı gibi dahili bir eylemden veya kesme veya sinyal gibi harici bir eylemden kaynaklanabilir.
Bu tanım, kontrol akışının bir kesme ile kesilebildiği ve bir kesme servis rutini (ISR) veya "işleyici" alt rutinine aktarılabildiği çoklu programlama ortamlarından kaynaklanmaktadır . İşleyici tarafından kullanılan ve kesme tetiklendiğinde potansiyel olarak yürütülüyor olabilecek herhangi bir alt yordam, yeniden girişli olmalıdır. Çoğu zaman, işletim sistemi çekirdeği aracılığıyla erişilebilen alt programlar, yeniden girişli değildir. Bu nedenle, kesme hizmeti rutinleri gerçekleştirebilecekleri eylemlerle sınırlıdır; örneğin, genellikle dosya sistemine erişimleri ve hatta bazen bellek ayırmaları kısıtlanır.
Bu yeniden giriş tanımı, çok iş parçacıklı ortamlarda iş parçacığı güvenliğinden farklıdır . Yeniden girişli bir alt yordam, iş parçacığı güvenliğini sağlayabilir, ancak tek başına yeniden girişli olmak, her durumda iş parçacığı güvenliği için yeterli olmayabilir. Tersine, iş parçacığı güvenli kodun mutlaka yeniden girişli olması gerekmez (örnekler için aşağıya bakın).
Yeniden giriş yapan programlar için kullanılan diğer terimler arasında "paylaşılabilir kod" bulunur. Yeniden giriş alt rutinleri bazen referans materyalinde "sinyal güvenli" olarak işaretlenir. Yeniden giriş programları genellikle "saf prosedürlerdir".
Arka plan
Yeniden giriş, işlevin birden fazla kez çağrılabildiği ancak yalnızca bir kez çağrılmış gibi tam olarak aynı çıktıyı ürettiği idempotence ile aynı şey değildir . Genel olarak konuşursak, bir fonksiyon bazı girdi verilerine dayalı olarak çıktı verileri üretir (genel olarak her ikisi de isteğe bağlıdır). Paylaşılan verilere herhangi bir zamanda herhangi bir işlev tarafından erişilebilir. Veriler herhangi bir işlev tarafından değiştirilebiliyorsa (ve hiçbiri bu değişiklikleri takip etmiyorsa), bir veriyi paylaşanların o verinin önceki herhangi bir zamanda aynı olduğuna dair bir garanti yoktur.
Verilerin bir programda nerede kullanılabileceğini açıklayan kapsam adı verilen bir özelliği vardır . Veri kapsamı ya geneldir ( herhangi bir işlevin kapsamı dışında ve belirsiz bir kapsamda) ya da yereldir (bir işlev her çağrıldığında oluşturulur ve çıkışta yok edilir).
Yerel veriler herhangi bir rutin tarafından paylaşılmaz, yeniden girilir veya girilmez; bu nedenle, yeniden girişi etkilemez. Genel veriler, işlevlerin dışında tanımlanır ve küresel değişkenler (tüm işlevler arasında paylaşılan veriler) veya statik değişkenler (aynı işlevin tüm çağrıları tarafından paylaşılan veriler ) biçiminde birden fazla işlev tarafından erişilebilir . In nesne yönelimli programlama , global veri bir sınıf kapsamında tanımlanır ve yalnızca bu sınıfın fonksiyonları için erişilebilir hale getirmek, özel olabilir. Bir sınıf değişkeninin bir sınıf örneğine bağlı olduğu örnek değişkenler kavramı da vardır . Bu nedenlerle, nesne yönelimli programlamada bu ayrım genellikle sınıf dışından erişilebilen (genel) veriler ve sınıf örneklerinden bağımsız (statik) veriler için ayrılmıştır.
Yeniden giriş, iş parçacığı güvenliğinden farklıdır, ancak bununla yakından ilişkilidir . Bir işlev iş parçacığı için güvenli olabilir ve yine de yeniden girişli olmayabilir. Örneğin, bir işlev bir muteks ile her tarafa sarılabilir (bu, çok iş parçacıklı ortamlarda sorunları önler), ancak bu işlev bir kesme hizmeti rutininde kullanılmışsa, ilk yürütmenin muteks'i serbest bırakmasını beklemekten ölebilir. Karışıklığı önlemenin anahtarı, yeniden girenin yalnızca bir iş parçacığı yürütmesine atıfta bulunmasıdır . Çoklu görev işletim sistemlerinin olmadığı zamanlardan kalma bir kavramdır.
Yeniden giriş kuralları
- Yeniden giriş kodu, serileştirme olmadan herhangi bir statik veya küresel sabit olmayan veriyi tutamaz .
- Yeniden giriş işlevleri küresel verilerle çalışabilir. Örneğin, bir yeniden giriş kesintisi hizmet rutini, çalışmak için (örneğin, seri bağlantı noktası okuma arabelleği) bir donanım durumu parçası alabilir ve bu yalnızca küresel değil, aynı zamanda geçicidir. Yine de, statik değişkenlerin ve genel verilerin tipik kullanımı tavsiye edilmez, çünkü serileştirilmemiş kod bölümleri dışında , bu değişkenlerde sadece atomik okuma-değiştirme-yazma talimatları kullanılmalıdır (bu mümkün olmamalıdır). böyle bir talimatın yürütülmesi sırasında gelecek bir kesinti veya sinyal). C'de, bir okuma veya yazmanın bile atomik olduğu garanti edilmediğine dikkat edin; birkaç okuma veya yazma işlemine bölünebilir. C standardı ve SUSv3
sig_atomic_t
, artırma veya azaltma için değil, yalnızca basit okuma ve yazma için garantiler verse de bu amacı sağlar. Daha karmaşık atomik işlemler sağlayan C11'de mevcutturstdatomic.h
. - Yeniden giriş kodu, serileştirme olmadan kendini değiştiremez .
- İşletim sistemi, bir işlemin kodunu değiştirmesine izin verebilir. Bunun çeşitli nedenleri vardır (örneğin, grafikleri hızlı bir şekilde blitting ), ancak bu , yeniden girişle ilgili sorunlardan kaçınmak için genellikle serileştirme gerektirir.
Ancak, kendi benzersiz belleğinde bulunuyorsa, kendini değiştirebilir. Yani, her yeni çağrı, orijinal kodun bir kopyasının yapıldığı farklı bir fiziksel makine kodu konumu kullanıyorsa, o belirli çağrının (iş parçacığının) yürütülmesi sırasında kendini değiştirse bile diğer çağrıları etkilemeyecektir.
- Yeniden giriş kodu, yeniden giriş yapmayan bilgisayar programlarını veya rutinlerini çağıramaz .
- Birden çok kullanıcı, nesne veya işlem önceliği veya çoklu işlem düzeyi, genellikle yeniden giriş kodunun kontrolünü karmaşıklaştırır. Reentrant olarak tasarlanmış bir rutin içinde yapılan herhangi bir erişim veya yan etkinin kaydını tutmak önemlidir.
İşletim sistemi kaynakları veya yerel olmayan veriler üzerinde çalışan bir alt yordamın yeniden girişi , ilgili işlemlerin atomitesine bağlıdır . Örneğin, alt program 32 bitlik bir makinede 64 bitlik bir global değişkeni değiştirirse, işlem iki 32 bitlik işleme bölünebilir ve böylece alt program yürütülürken kesintiye uğrar ve kesme işleyicisinden yeniden çağrılırsa , global değişken yalnızca 32 bitin güncellendiği bir durumda olabilir. Programlama dili, atlama veya çağrı gibi dahili bir eylemin neden olduğu kesintiler için atomite garantileri sağlayabilir. Daha sonra, bir programlama dilinde alt ifadelerin değerlendirme sırasının keyfi olabileceği f
gibi bir ifadedeki işlev (global:=1) + (f())
, global değişkenin ya 1'e ya da önceki değerine ayarlandığını görecek, ancak yalnızca bir kısmının olduğu bir ara durumda değil. güncellenmiş. (Sonuncusu C'de olabilir , çünkü ifadenin sıra noktası yoktur .) İşletim sistemi , kısmi bir etkiye sahip olmayan bir sinyal tarafından kesilen bir sistem çağrısı gibi, sinyaller için atomik garantiler sağlayabilir . İşlemci donanım için bölünmezlik garanti sağlayabilir kesme gibi kısmi etkilere sahip olmayan kesintiye işlemci talimatları gibi.
Örnekler
Yeniden girişi göstermek için, bu makale örnek olarak iki işaretçi alıp değerlerini değiştiren bir C yardımcı program işlevini swap()
ve takas işlevini de çağıran bir kesme işleme yordamını kullanır.
Ne reentrant ne de thread güvenli
Bu, yeniden girişli veya iş parçacığı için güvenli olamayan örnek bir takas işlevidir. Yana tmp
değişken küresel paylaşılır ve senkronizasyon gerekmeden, fonksiyonun herhangi eşzamanlı örnekleri arasında, bir örneği verileri başka dayanmadığınızı engel olabilir. Bu nedenle, kesme hizmeti rutininde kullanılmamış olmalıdır isr()
:
int tmp;
void swap(int* x, int* y)
{
tmp = *x;
*x = *y;
/* Hardware interrupt might invoke isr() here. */
*y = tmp;
}
void isr()
{
int x = 1, y = 2;
swap(&x, &y);
}
İplik güvenli ancak reentrant değil
swap()
Önceki örnekteki işlev , tmp
thread-local yapılarak iş parçacığı için güvenli hale getirilebilir . Hâlâ reentrant olmayı başaramıyor ve bu, isr()
halihazırda yürütülmekte olan bir iş parçacığıyla aynı bağlamda çağrılırsa sorunlara neden olmaya devam edecek swap()
:
_Thread_local int tmp;
void swap(int* x, int* y)
{
tmp = *x;
*x = *y;
/* Hardware interrupt might invoke isr() here. */
*y = tmp;
}
void isr()
{
int x = 1, y = 2;
swap(&x, &y);
}
Reentrant ancak iş parçacığı için güvenli değil
Genel verileri çıkarken tutarlı bir durumda bırakmaya özen gösteren takas işlevinin aşağıdaki (biraz yapmacık) değişikliği yeniden girişlidir; ancak, kullanılan hiçbir kilit olmadığından iş parçacığı için güvenli değildir, herhangi bir zamanda kesilebilir:
int tmp;
void swap(int* x, int* y)
{
/* Save global variable. */
int s;
s = tmp;
tmp = *x;
*x = *y; /*If hardware interrupt occurs here then it will fail to keep the value of tmp. So this is also not a reentrant example*/
*y = tmp; /* Hardware interrupt might invoke isr() here. */
/* Restore global variable. */
tmp = s;
}
void isr()
{
int x = 1, y = 2;
swap(&x, &y);
}
Reentrant ve iş parçacığı güvenli
Bir uygulanması swap()
o ayırır tmp
üzerinde yığının yerine küresel ve bu sadece parametre olarak paylaşılmamış değişkenlerle denir hem iş parçacığı güvenli ve yeniden yapılandırılmıştır. Yığın bir iş parçacığı için yerel olduğundan ve yalnızca yerel verilere etki eden bir işlev her zaman beklenen sonucu üreteceğinden iş parçacığı güvenlidir. Paylaşılan verilere erişim yoktur, bu nedenle veri yarışı yoktur.
void swap(int* x, int* y)
{
int tmp;
tmp = *x;
*x = *y;
*y = tmp; /* Hardware interrupt might invoke isr() here. */
}
void isr()
{
int x = 1, y = 2;
swap(&x, &y);
}
Reentrant kesme işleyicisi
Yeniden giren bir kesme işleyicisi, kesme işleyicisinde erken kesmeleri yeniden etkinleştiren bir kesme işleyicisidir. Bu, kesme gecikmesini azaltabilir . Genel olarak, kesme servis rutinlerini programlarken, kesme işleyicisinde mümkün olan en kısa sürede kesmelerin yeniden etkinleştirilmesi önerilir. Bu uygulama, kesintilerin kaybolmasını önlemeye yardımcı olur.
Diğer örnekler
Aşağıdaki kodda, ne işlevler ne f
de g
işlevler reentrant değildir.
int v = 1;
int f()
{
v += 2;
return v;
}
int g()
{
return f() + 2;
}
Yukarıda, f()
sabit olmayan bir global değişkene bağlıdır v
; bu nedenle, f()
yürütme sırasında değiştiren bir ISR tarafından kesintiye uğrarsa v
, içine yeniden giriş f()
yanlış değerini döndürür v
. değeri v
ve dolayısıyla dönüş değeri f
güvenle tahmin edilemez: 'in yürütülmesi v
sırasında bir kesmenin değiştirilip değiştirilmediğine bağlı olarak değişir f
. Dolayısıyla f
reentrant değildir. İkisi de değildir g
, çünkü çağırır f
, ki bu reentrant değildir.
Bunlar biraz değişmiş versiyonu olan evresel:
int f(int i)
{
return i + 2;
}
int g(int i)
{
return f(i) + 2;
}
Aşağıda, işlev iş parçacığı için güvenlidir, ancak (zorunlu olarak) yeniden girişli değildir:
int function()
{
mutex_lock();
// ...
// function body
// ...
mutex_unlock();
}
Yukarıda, function()
herhangi bir sorun olmadan farklı iş parçacıkları tarafından çağrılabilir. Ancak, işlev bir yeniden giriş kesme işleyicisinde kullanılıyorsa ve işlev içinde ikinci bir kesinti ortaya çıkarsa, ikinci rutin sonsuza kadar askıda kalır. Kesinti hizmeti diğer kesintileri devre dışı bırakabileceğinden, tüm sistem bundan zarar görebilir.
Notlar
Ayrıca bakınız
Referanslar
Atıfta bulunulan eserler
- Kerrisk, Michael (2010). Linux Programlama Arayüzü . Nişasta Presi yok .
- Ralston, Anthony , ed. (2000). "Yeniden Giriş Programı". Bilgisayar Bilimleri Ansiklopedisi (4. baskı). Doğa Yayın Grubu .
- Sloss, Andrew N.; Symes, Dominik; Wright, Chris ; Rayfield, John (2004). ARM Sistem Geliştirici Kılavuzu . Morgan Kaufmann Yayıncılar. ISBN'si 9780080490496.
daha fazla okuma
- Chen, Raymond (2004-06-29). "İplik güvenliği ve yeniden giriş arasındaki fark" . Eski Yeni Şey . Microsoft Geliştirici Ağı . 2018-04-24 tarihinde kaynağından arşivlendi . 2018-04-24 alındı .
- Ganssle, Jack (2001-03-15). "Reentrancy'ye Giriş" . Gömülü.com . 2013-01-21 tarihinde kaynağından arşivlendi . 2018-04-24 alındı .
- IBM (2018). "Genel Programlama Kavramları" (PDF) . AIX Sürüm 7.2 Kılavuzu . P. 636-641 . 2018-04-24 alındı .
- Jha, Dipak (2005-01-20). "Daha Güvenli Sinyal İşleme için Yeniden Giriş İşlevlerini Kullanın" . IBM DeveloperWorks . 2014-07-07 tarihinde kaynağından arşivlendi . 2018-04-24 alındı .