Proper maintenance and care of multi-threading locks
Aşağıdaki stratejiler, kodun dead-lock'suz olmasını sağlamak için kullanılmaktadır (genellikle 4. Coffman koşulunu: dairesel beklemeyi ele alarak).
- structure code such that only one lock will need to be acquired at a time
- her zaman aşağıdaki tabloda verilen sırayla paylaşılan kilitleri aynı sırayla alın
- sınırsız özyineleme gerektirecek yapıları kullanmaktan kaçının
Locks
Aşağıda sistemde mevcut olan tüm kilitler ve bunları kullanma mekanizmaları, potansiyel ölü kilitlenmeleri önlemek için (burada Ostrich algoritması yoktur) bulunmaktadır:
Aşağıdakiler kesinlikle yaprak kilitleridir (seviye 1) ve başka bir kilit edinmeye çalışmamalıdır:
safepoint
Not edin ki bu kilit,
JL_LOCK
veJL_UNLOCK
tarafından örtük olarak edinilir. Seviye 1 kilitler için bunu önlemek amacıyla_NOGC
varyantlarını kullanın.Bu kilidi tutarken, kodun herhangi bir tahsisat yapmaması veya herhangi bir güvenli noktaya ulaşmaması gerekir. Tahsisat yaparken, GC'yi etkinleştirirken/devre dışı bırakırken, istisna çerçevelerine girerken/geri yüklerken ve kilit alırken/serbest bırakırken güvenli noktaların olduğunu unutmayın.
paylaşılan_harita
sonlandırıcılar
sayfa tahsisi
gcpermlock
flisp
jlinstackwalk (Win32)
ResourcePool<?>::mutex
RLST_mutex
llvmbasamakmutex
jlkilitliakış::mutex
debuginfo_asyncsafe
çıkarımzamanamutex
ExecutionEngine::SessionLock
flisp kendisi zaten thread güvenliğidir, bu kilit yalnızca
jl_ast_context_list_t
havuzunu korur, ayrıca ResourcePool<?>::mutexes yalnızca ilişkili kaynak havuzunu korur.
Aşağıda bir yaprak kilidi (seviye 2) bulunmaktadır ve yalnızca dahili olarak seviye 1 kilitleri (güvenli nokta) alır:
- globalrootslock
- Modül->kilit
- JLDebuginfoPlugin::PluginMutex
- yeniçıkarılanmutex
Aşağıda yalnızca dahili olarak seviye 1 veya seviye 2 kilitleri alabilen seviye 3 bir kilit bulunmaktadır:
- Yöntem->yazma kilidi
- typecache
Aşağıda yalnızca seviye 1, 2 veya 3 kilitleri almak için geri dönebilme yeteneğine sahip seviye 4 bir kilit bulunmaktadır:
- MethodTable->yazma kilidi
Bu noktadan yukarıda bir kilit tutarken hiçbir Julia kodu çağrılmamalıdır.
orc::ThreadSafeContext (TSCtx) kilitleri, kilitleme hiyerarşisinde özel bir yere sahiptir. LLVM'nin küresel, çok iş parçacıklı olmayan durumunu korumak için kullanılırlar, ancak bunlardan keyfi sayıda olabilir. Varsayılan olarak, bu kilitlerin tümü, hiyerarşinin geri kalanıyla karşılaştırma amacıyla seviye 5 kilitleri olarak kabul edilebilir. Bir TSCtx edinmek yalnızca JIT'in TSCtx havuzundan yapılmalıdır ve o TSCtx üzerindeki tüm kilitler, havuza geri döndürülmeden önce serbest bırakılmalıdır. Birden fazla TSCtx kilidinin aynı anda edinilmesi gerekiyorsa (özyinelemeli derleme nedeniyle), kilitler, TSCtx'lerin havuzdan ödünç alındığı sıraya göre edinilmelidir.
Aşağıdaki seviye 5 kilittir
- JuliaOJIT::EmissionMutex
Aşağıdakiler, yalnızca daha düşük seviyelerde kilitler almak için yinelemeli olarak çalışabilen seviye 6 bir kilittir:
- kod üreteci
- jlmodüllermutex
Aşağıdaki neredeyse kök kilidi (seviye son-1) anlamına gelir, yani onu edinmeye çalışırken yalnızca kök kilidi tutulabilir:
typeinf
bu belki de en karmaşık olanlardan biri, çünkü tür çıkarımı birçok noktadan çağrılabilir.
şu anda kilit, birbirlerini özyinelemeli olarak çağırdıkları için kod oluşturma kilidi ile birleştirilmiştir.
Aşağıdaki kilit, IO işlemlerini senkronize eder. Yukarıda listelenen diğer kilitlerden herhangi birini tutarken herhangi bir I/O (örneğin, uyarı mesajları veya hata ayıklama bilgileri yazdırmak) yapmanın, kötü ve zor bulunabilen ölümlere yol açabileceğini unutmayın. ÇOK DİKKATLİ OLUN!
iolock
Bireysel ThreadSynchronizers kilitleri
bu, iolock'u serbest bıraktıktan sonra devam edebilir veya onsuz edinilebilir, ancak iolock'u tutarken asla edinmeye çalışmamaya dikkat edin.
Libdl.TembelKütüphane kilidi
Aşağıdaki kök kilit, onu almaya çalışırken başka bir kilidin tutulamayacağı anlamına gelir:
üst seviye
bu, yeni bir tür oluşturmak veya yeni bir yöntem tanımlamak gibi üst düzey bir eylem gerçekleştirilmeye çalışılırken tutulmalıdır: sahnelenmiş bir işlev içinde bu kilidi elde etmeye çalışmak bir kilitlenme durumuna neden olacaktır!
ek olarak, herhangi bir kodun rastgele bir üst düzey ifade ile güvenli bir şekilde paralel çalışıp çalışamayacağı belirsizdir, bu nedenle tüm iş parçacıklarının önce bir güvenli noktaya ulaşması gerekebilir.
Broken Locks
Aşağıdaki kilitler bozulmuştur:
üst seviye
şu anda mevcut değil
düzelt: oluşturun
Modül->kilit
Bu, sıralı olarak edinildiğinden emin olamayacağı için deadlock'lara karşı savunmasızdır. Bazı işlemler (örneğin
import_module
) bir kilit eksik.düzelt:
jl_modules_mutex
ile değiştir?loading.jl:
require
veregister_root_module
Bu dosyada potansiyel olarak birçok sorun var.
düzelt: kilitlere ihtiyaç var
Shared Global Data Structures
Bu veri yapıları, paylaşılan değişken küresel durumu nedeniyle kilitlere ihtiyaç duyar. Bu, yukarıdaki kilit öncelik listesinin tersidir. Bu liste, basitlikleri nedeniyle seviye 1 yaprak kaynaklarını içermez.
MethodTable değişiklikleri (def, cache) : MethodTable->yazma kilidi
Tip bildirimleri: üst düzey kilit
Uygulama türü: typecache kilidi
Küresel değişken tabloları : Modül->kilit
Modül serileştirici : üst düzey kilit
JIT ve tür çıkarımı: kod oluşturma kilidi
MethodInstance/CodeInstance güncellemeleri : Method->yazma kilidi, kod oluşturma kilidi
Bunlar inşaatta belirlenir ve değiştirilemez:
- specTürleri
- sparam_vals
- def
- sahip
Bunlar
jl_type_infer
tarafından belirlenir (kod oluşturma kilidi tutulurken):
- önbellek
- rettype
- çıkarılan
* valid ages
inInference
bayrağı:
jl_type_infer
çalışırken tekrarına hızlıca girmeyi önlemek için optimizasyon- gerçek durum (
çıkarılan
, ardındanfptr
ayarı) kod üretim kilidi ile korunmaktadır
Fonksiyon işaretçileri:
- bu geçişler bir kez,
NULL
'dan bir değere, kod oluşturma kilidi tutulurken gerçekleşirKod üreteci önbelleği (
functionObjectsDecls
içeriği):
- bunlar birden fazla kez geçiş yapabilir, ancak yalnızca kod üretim kilidi tutulduğunda
- eski sürümünü kullanmak geçerlidir veya bunun yeni sürümleri için engel oluşturmak, bu nedenle yarışlar zararsızdır, yeter ki kod, yöntem örneğindeki diğer verilere (örneğin
rettype
) atıfta bulunmamaya dikkat etsin ve bunun koordine olduğunu varsaymasın, aksi takdirde kod oluşturma kilidini de tutmalıdır.
LLVMContext : kod oluşturma kilidi
Yöntem : Yöntem->yazma kilidi
- kökler dizisi (serileştirici ve kod üreteci)
- çağır / uzmanlıklar / tfunc değişiklikleri