Eşzamanlılık (Thread'ler & Mutex'ler)
Tulpar OS thread’lerini doğrudan üç yerleşik fonksiyon üzerinden
sunar: thread_create, mutex_create ve mutex_lock /
mutex_unlock çifti. Bunlar gerçek OS thread’leridir — her
thread_create çağrısı bir tane başlatır, dolayısıyla kilitlerle iş
birliği sizin sorumluluğunuzdadır. Kooperatif, tek-thread’li
eşzamanlılık (bloklamayan timer ve HTTP) için bunun yerine
Async / Await’e bakın.
Thread başlatma
Section titled “Thread başlatma”thread_create(handler_adi, arg) ilk argümanın adıyla belirtilen
fonksiyonu çağıran yeni bir thread başlatır ve ikinci argümanı tek bir
değer olarak ona iletir. Dönüş bir thread id’sidir (int); join
etmeyecekseniz thread_detach(id) ile eşleştirin.
func isci(arg) { print("Isçi çalışıyor, arg =", arg);}
int t = thread_create("isci", 42);thread_detach(t);Handler ilk çalıştığında ada (string) göre aranır ve önbelleğe
alınır, dolayısıyla AOT pipeline’ının dışa aktardığı bir üst seviye
fonksiyon olmalıdır (her func tanımı için varsayılan).
Paylaşılan durumu koruma
Section titled “Paylaşılan durumu koruma”Birden fazla thread’in mutasyona uğrattığı bir sayaç klasik yarış
durumudur. Oku-değiştir-yaz bölgesini mutex_lock / mutex_unlock
ile sarın:
int sayac = 0;int mu = mutex_create();
func arttir(arg) { mutex_lock(mu); sayac = sayac + 1; mutex_unlock(mu);}
for (int i = 0; i < 100; i++) { int t = thread_create("arttir", i); thread_detach(t);}
sleep(100); // thread'lerin bitmesi için biraz zaman verprint("sayac =", sayac);Kilidi tutabildiğiniz en kısa bölge için tutun — tipik olarak
sadece paylaşılan duruma yazma. lib/wings.tpr içindeki HTTP sunucusu
tam bu deseni kullanır: handler dispatch çevresinde kilitler, response
inşa edilip gönderilmeden önce kilidi açar.
Çalışan örnek: thread’li HTTP sunucusu
Section titled “Çalışan örnek: thread’li HTTP sunucusu”lib/wings.tpr (Wings framework’u) ana döngüsünde yeni TCP
bağlantılarını kabul eder ve her bağlantıyı bir worker thread’ine
verir. Çekirdek deyim şöyle görünür:
import "wings";
func handle_root() { return wings_text("merhaba thread " + toString(thread_id()));}
get("/", "handle_root");listen(8080); // wings dahili olarak bağlantı başına thread başlatırTüm framework için HTTP Sunucusu (Wings)
sayfasına bakın — thread’leme listen içinde gerçekleşir, yaygın
durum için bunu kendiniz bağlamak zorunda değilsiniz.
Pratik kurallar
Section titled “Pratik kurallar”- Küçük değer iletin.
thread_createtek arg alır. Daha fazla bağlam için birarrayJsoniçine paketleyip worker’da çıkartın. - Sadece paylaşılan yazma çevresinde kilit. Değişmez verilerin okunması kilit gerektirmez; tek global kilit yerine kaynak başına mutex kullanın.
- Join etmiyorsanız detach edin. Sızdırılmış thread handle’ı asla geri alınmayacak gerçek bir OS thread’idir.
- Sleep senkronizasyon değildir.
sleep(ms)koşul beklemek için değil, hız ayarlamak içindir. Bir koşul beklemek için mutex + worker’ın set ettiği bir bayrak kullanın.
Async / await (kooperatif coroutine’ler)
Section titled “Async / await (kooperatif coroutine’ler)”OS thread’lerinden ayrı olarak Tulpar, tek bir iş parçacığında kooperatif
eşzamanlılık için async / await sunar (v3.0.0’da eklendi). Bir
async func hemen bir promise döndürür; await ise o promise yerleşene
kadar çağıranı askıya alır ve bu sırada diğer coroutine’lerin çalışmasına
izin verir.
async func yavas_iki_kat(int n) { await sleep_async(20); // bloklamayan duraklama — diğer işler çalışır return n * 2;}
async func selamla(str kim) { await sleep_async(10); print("merhaba " + kim); return 1;}
// İki coroutine başlat; biz await ederken eşzamanlı çalışırlar.var a = yavas_iki_kat(21);var g = selamla("dunya");
int sonuc = await a; // 42await g;print("bitti");yavas_iki_kat ilk başlatılıp ilk await edilmesine rağmen selamla
(10 ms timer) ondan (20 ms) önce biter — iki coroutine’in bloklamak
yerine iç içe geçtiğinin kanıtı.
Nasıl çalışır
Section titled “Nasıl çalışır”async funcbir coroutine’e derlenir. Çağırmak task’ı başlatır ve bekleyen bir promise döndürür; gövde, event loop onu sürene kadar (bir sonrakiawait’te ya da program sonunda) çalışmaz.await ifade—ifadebir promise ise yerleşene dek askıya alır ve değerini verir; coroutine içindeyse kontrolü scheduler’a, ana akıştaysa loop’u sürerek hazır olana dek bekler. Promise olmayan bir değerdeawaitbirim işlevdir (await 5 == 5).sleep_async(ms)msmilisaniye sonra bloklamadan yerleşen bir promise döndürür — bloklayansleep(ms)’in aksine. Bloklamayan gecikme içinawait sleep_async(ms)kullanın.- Runtime program sonunda bekleyen tüm task’ları drene eder; başlatılıp await edilmemiş bir coroutine bile tamamlanır (Node tarzı).
Bir coroutine başka bir coroutine’i await edebilir; böylece async fonksiyonları besteleyebilirsin:
async func artir(int x) { await sleep_async(2); return x + 1; }async func zincir(int x) { int a = await artir(x); int b = await artir(a); return b;}print(await zincir(40)); // 42