Delphi ile Thread(Kanal) Kullanımı – Bölüm 2
Bu bölümde kanalları nasıl eş zamanlı olarak çalıştırabileceğinizi göreceksiniz. Bunun için kritik bölgeler ve muteksler ile tanışacaksınız. Ayrıca kanal uyumlu olmayan VCL’in, kanallar ile nasıl kullanılabileceğini de göreceksiniz. Bununla beraber kanal kullanımındaki yaşanan bazı problemlere de değinmeye çalışacağız. Özellikle veritabanlarını kanallar ile kullanmada uyulması gereken püf noktalarına da değinmeye çalışacağız.
Aslında bu bölüm gerçekten uzun oldu. Normalde VCL kullanımını üçüncü bir bölüme taşımayı düşünüyordum. Ama bu konuda istekler olunca birleştrip yayınlamayı düşüdüm. İçeride sizi iki sayfalık bir makale bekliyor. Bu yüzden sayfa sonunda bitti zannedip kapatmayın!
Hazırsanız başlayalım.
Kanallar’ı Eş Zamanlı Olarak Çalıştırmak
Kanallar ile uğraşırken karşılaşılan en büyük sorunlardan bir tanesi de şüphesiz kanalları ortak bir şekilde sorunsuz olarak çalıştırmaktır. Eminim kanallar ile uğraşan birisi bütün kanallar tarafından ortak olarak kullanılan bir kaynağa erişmede problemlerle karşı karşıya gelmiştir ve kanalları bir köşeye itmesine sebep olmuştur.
Mesela şu veritabanı problemi size tanıdık gelecektir. Diyelim ki, iki adet kanalımız var ve bunlardan birincisi veritabanındaki bir kaydı açıp değişiklik yapmaya başladı. Sonra ikinci kanal aynı kaydın belli bölümlerinde düzenlemeler yaptıktan sonra veriyi kaydetti. Ardından birinci kanal, aynı verilerdeki değişikliğini bitirdi ve kaydetti. Birinci kanal, ikinci kanal’ın değişikliklerinden habersiz olduğundan ikinci kanalın yaptığı düzenlemeler de uçtu gitti.
Burada okuduğunuz problem, normalde kanallar ve veritabanı ile uğraşan bir çok programcının başına gelmiş bir problemdir. Bununla birlikte sadece veritabanında değil bir çok noktada özellikle bir dosyayı, bir portu, bir DLL’i veya başka bir şeyi, kanalların ortak kullanmasında hep benzer sıkıntılarla karşılaşılmıştır. Bu gibi sıkıntıların ve problemlerin çözümü kanalları eş zamanlı kullanım için kritik bölgeler tanımlamak ya da muteksleri kullanmaktır. Bu iki yöntem de makalemizin konuları arasındadır.
Kritik Bölgeler(Critical Sections)
Kritik Bölgeler -ya da başka yerlerde görebileceğiniz gibi kritik kesimler, bölümler, vs..- yukarıda anlatığımız problemdeki, birinci kanalın kaynağı kullanması esnasında ikinci kanalın bu kaynağa erişmesini englelemek için kullanılır. Birinci kanal işini yapıyorken, ikinci kanal’a çalışması için bir zaman dili ayrılmaz. Böylece birinci kanal işini bitirene kadar ikinci kanal çalıştırılmaz.
Bunun için örnek bir uygulamada yukarıdaki anlattığımız senaryolara benzer bir problem oluşturalım ve çözümünü aramaya çalışalım.
Diyelim ki, iki adet kanalımız var ve bu kanallar bir döngünün her adımında bir dizi işlem gerçekleştiriyor. Ve bu gerçekleştirdikleri işlemler için ortak kullandıkları global olarak tanımlanmış bir değişken olsun. Meseleyi anlatabilmek için iki kanalında yaptığı işlemlerin sonucunun aynı olmasını sağlamak istiyorum. Böylece problem daha iyi anlaşılabilecek.
Birinci kanal bir döngünün her adımında global değişkenimize teker teker harfler ekliyor ve sonuçta değişkenimizde bir yazı oluşuyor. Aynı işlemi ikinci kanalımız da yapıyor ve sonuç olarak birinci kanal ile aynı yazıyı üretiyorlar. Yanlız ikinci kanal harfleri teker teker eklemek yerine ikişer ikişer ekliyor. Ekleme işlemi çok hızlı olduğundan problemin oluşması için aralara Sleep rutinini ekleyerek işlemi birazcık yavaşlatıyoruz. Şimdi bu mantığımızı koda dökmeye başlayalım.
Yeni bir VCL uygulaması açalım ve bir adet button ekleyelim. Aşağıdaki gibi unitin var bloğunda global bir değişken tanımlayalım:
var Form1: TForm1; SonucYazi: string; //Global değişkenimiz
Ardından buttonun OnClick olayını aşağıdaki gibi değiştirelim.
procedure TForm1.Button1Click(Sender: TObject); var Kanal1ID, Kanal2ID: DWORD; begin CreateThread(nil, 0, @Kanal1, nil, 0, Kanal1ID); CreateThread(nil, 0, @Kanal2, nil, 0, Kanal2ID); end;
Bu iki adet kanalımıza ait kanal fonksiyonlarını da aşağıdaki gibi oluşturalım:
procedure Kanal1;
procedure Kanal2;
...
implementation
...
procedure Kanal1;
var
i: Integer;
begin
for i := 0 to 10 do
begin
SonucYazi := SonucYazi + 'd';
Sleep(10);
SonucYazi := SonucYazi + 'i';
SonucYazi := SonucYazi + 'y';
SonucYazi := SonucYazi + 'e';
Sleep(10);
SonucYazi := SonucYazi + 'z';
SonucYazi := SonucYazi + 'o';
SonucYazi := SonucYazi + 'n ';
Sleep(10);
end;
end;
procedure Kanal2;
var
i: Integer;
begin
for i := 0 to 10 do
begin
SonucYazi := SonucYazi + 'di';
Sleep(10);
SonucYazi := SonucYazi + 'ye';
SonucYazi := SonucYazi + 'zo';
Sleep(10);
SonucYazi := SonucYazi + 'n ';
end;
end;Gördüğünüz gibi iki kanal fonksiyonu da aynı sonucu üretiyor. Ama sonucu üretme yolları farklı. Ayrıca iki kanal da peş peşe oluşturulup çalıştırılıyor. Forma bir adet daha button ekleyelim ve bize sonucu göstersin. Bunun için ikinci butonumuzun OnClick olayını aşağıdaki gibi düzenleyelim:
procedure TForm1.Button2Click(Sender: TObject); begin ShowMessage(SonucYazi); end;
Bu programı çalıştırdıktan sonra ve kanalları birinci düğme ile çalıştırdıktan sonra sonuç yazının "diyezon diyezon diyezon …" gibi bir şey olmasını isteriz. Yani bir for döngüsünün bir adımı tamamlanmadan SonucYazi isimli global değişkene müdahale olmasını istemeyiz. Halbuki programı çalıştırdığınızda sonucun hiç de böyle olmadığını göreceğiz. Kanal1 işini bitirip "diyezon " yazmadan Kanal2 işe karışmış ve aralarda kendi harflerini eklemiştir. Hakeza bu, Kanal2 için de geçerlidir. Yani Kanal2, döngünün bir adımını bitirip istenilen sonucu veremeden Kanal1 global değişkenimize müdahale etmiştir.
Burada verdiğimiz örnek biraz soyut kaçabilir. Çünkü yaptığımız işlemden sonuç olarak elimize bir şey geçmiyor. Ama karşılaşacağınız sorunlar hep bu tarzda sorunlardır. Karşılaştığınız sorunları verdiğimiz bu örnek ile kıyaslama yapabilirsiniz. Mesela biz bu örneğimizde işlem adımlarını yavaşlatmak için Sleep rutinini kullandık. Normal hayatta kanallar ile uğraşırken zaten yaptığımız işlemlerin adımları Sleep rutinini aratmamaktadır. Mesela bir veritabanı tablosunda Edit ve Post gibi metodları kullandığımızda belli bir miktar işlemin tamamlanmasını bekleriz. Bir de eğer sizde sonuç düzgün çıkıyorsa yine söylüyorum işlemciniz, bu makaleyi yazdığım sıralardaki işlemcimden hızlı demektir. Bu durumda Sleep rutinine verdiğimiz değerleri çok az miktarlarda artırmayı deneyin.
Sadede gelelim ve problemi anladı isek şöyle bir soruyu kafamıza getirelim: Bir kanal belli bir işini bitirmeden önce diğer kanalların müdahalesini nasıl engelleyebiliriz?
Cevabı zaten bu bölümün başında verdik. Bunun için belli yerleri kritik bölge ilan edeceğiz. Bir kanalda kritik bölge ilan ettiğimiz yerdeki kodlar çalışmaya başladığı sırada, diğer kanallardaki aynı kritik bölgedeki kodlar işletilmez ve bekler. Yani aynı kritik bölgeye sahip kanallardan aynı anda sadece bir bölgedeki kodlar çalıştırılabilir. Böylece diğer kanalların istenilmeyen müdahalesi engellenmiş olur.
Bir Kritik bölge tanımlamak için bilmemiz gereken üç dört adet Windows apisi vardır.
InitializeCriticalSection: Bu fonksiyon kritik bölge’yi temsil eden recordun ilk değerlerini atamakla sorumludur. Yani kritik bölgeyi kullanıma hazırlamaktadır. Genelde formun OnCreate olayında kullanılır.
DeleteCriticalSection: Yukarıdaki fonksiyonun tam tersi olarak, bu fonksiyon da kritik bölgeyi ortadan kaldırır. Genelde formun OnDestroy olayına yerleştirilir.
EnterCriticalSection: Bu fonksiyonu çalıştırdığınız satırdan itibaren kritik bölgenin başlangıcını belirtirsiniz. Yani Delphi’deki "begin" kelimesi gibi düşünebilirsiniz.
LeaveCriticalSection: Bu fonksiyon ise, çalıştırıldığı satırla kritik bölgeyi sınırlandırır. Yine Delphi’deki "end" ifadesine benzetebiliriz.
Kritik bölgeyi temsil eden record ise TRTLCriticalSection tipindedir. Normalde Windows SDK yardım dosyalarında LPCRITICAL_SECTION şeklinde tanımlanmıştır. Ama Delphi ekibi bir çok windows yapısını tanımlarken bunlara "T" ile başlayan daha iyi okunur alias isimler vermişler. Her neyse…
Kritik bölgenin tanımlanması gayet basittir. Bir kritik bölgeyi işletim sistemine tanıtmak için InitializeCriticalSection fonksiyonunu kullanıyoruz. Kritik bölge ile işimiz bittiğinde de DeleteCriticalSection fonksiyonunu çağırmayı unutmuyoruz. Ardından kanal fonksiyonlarımızda kritik bölgeleri belirleyip başına EnterCriticalSection ve sonuna LeaveCriticalSection sonksiyonlarını koyuyoruz.
Örneğimize dönelim ve kritik bölgeleri eklemeye başlayalım. Bizim müdahale istemediğimiz bölge, kanal fonksiyonlarındaki döngülerin her bir adımıdır. Yani teker teker veya ikişer ikişer ekleme yapılan kısımlarda bir adım işini bitirmeden başka bir kanalın global değişkenimize müdahalesini engellemek istiyoruz. Kısacası kritik bölgemiz bu örnekte, döngünün her bir adımı olmalıdır.
İlk başta global olarak bir değişken daha tanımlayalım. Bu değişken bizim kritik bölgemizi temsil eden record olsun.
var Form1: TForm1; SonucYazi: string; BirinciKritikBolge: TRTLCriticalSection; //kritik bölgemizi temsil ediyor.
Ardından formun OnCreate ve OnDestroy olaylarını aşağıdaki gibi değiştirelim.
procedure TForm1.FormCreate(Sender: TObject); begin InitializeCriticalSection(BirinciKritikBolge); end; procedure TForm1.FormDestroy(Sender: TObject); begin DeleteCriticalSection(BirinciKritikBolge); end;
Eğer başka kritik bölgeler de tanımlamış iseniz bunları da InitializeCriticalSection ve DeleteCriticalSection fonksiyonlarını kullanarak oluşturmalı ve silme işlemlerini gerçekleştirmelisiniz. Bizim örneğimizde bir adet kritik bölge yeterlidir.
Şimidi kanal fonksiyonlarında bahsettiğimiz yerleri kritik bölge olarak ilan edelim.
procedure Kanal1;
var
i: Integer;
begin
for i := 0 to 10 do
begin
EnterCriticalSection(BirinciKritikBolge); //BirinciKritikBolge başlangıcı
SonucYazi := SonucYazi + 'd';
Sleep(10);
SonucYazi := SonucYazi + 'i';
SonucYazi := SonucYazi + 'y';
SonucYazi := SonucYazi + 'e';
Sleep(10);
SonucYazi := SonucYazi + 'z';
SonucYazi := SonucYazi + 'o';
SonucYazi := SonucYazi + 'n ';
Sleep(10);
LeaveCriticalSection(BirinciKritikBolge); //BirinciKritikBolge bitişi
end;
end;
procedure Kanal2;
var
i: Integer;
begin
for i := 0 to 10 do
begin
EnterCriticalSection(BirinciKritikBolge); //BirinciKritikBolge başlangıcı
SonucYazi := SonucYazi + 'di';
Sleep(10);
SonucYazi := SonucYazi + 'ye';
SonucYazi := SonucYazi + 'zo';
Sleep(10);
SonucYazi := SonucYazi + 'n ';
LeaveCriticalSection(BirinciKritikBolge); //BirinciKritikBolge bitişi
end;
end;Yapacağımız başka bir işlem kalmadı. Programı çalıştırıp deneybiliriz. Sonucun "diyezon diyezon diyezon …" gibi düzgün olduğunu göreceğiz. Çünkü Kritik bölge tanımlayarak sadece bir kanalın kritik bölgesini çalıştırmış olduk. Böylece bir kanal global SonucYazi değişkeni ile uğraşırken diğer kanal buna müdahale edemeyecektir.
Burada bir adet kritik bölge tanımladık. Sizler ihtiyaca göre projelerinizde bir çok kritik bölge tanımlayabilirsiniz. Ayrıca kritik bölgelerin birbirinden bağımsız hareket ettiğini de aklınızdan çıkarmayın. Bazen karıştırılan nokta bu kısım olabiliyor. Mesela bu örneğimizde bir adet kritik bölge mevcut ama iki farklı yapılan iş var.
Gördüğünüz gibi kanalları eş zamanlı olarak çalıştırmak o kadar da zor değilmiş. Tek yaptığımız bell bölgeleri kritik bölge olarak ilan etmek. Şimdi yeni bir kavramla daha tanışalım.
Muteksler(Mutex)
İngilizce’ de, mutual ve exclusive kelimelerinin birleşiminden meydana gelmiştir. Dilimizde ise müşterek ve seçkin kelimeleri bu kelimeleri karşılamaktadır. Programlama terminolojisinde ise, sadece tek işlemdeki değil birden fazla işlemdeki kanalları eş zamanlı olarak kullanılmasını sağlayan bir tekniktir.
Bir mutekse aynı anda sadece bir tek kanal sahip olabilir. Literatürde, bu mutekse, bir kanal sahip olduğunda, muteksin kanal tarafından "tetiklendiği" ya da "tutulduğu" söylenir. Aynı şekilde eğer kanal bu mutekse sahip deiğilse muteks "serbestir" ya da "tetiklenmemiştir" tabirleri kullanılır.
Şu an kafanızda mutekslerin ne olduğuna dair somut bir düşünce oluşmamış olabilir. Ama bölümün sonuna kadar okuduğunuzda neyin ne olduğuna dair bir fikir oluşacağına eminim.
Bir muteks, CreateMutex fonksiyonu ile oluşturulur. Bu fonksiyonun tanımlanması ve açıklaması aşağıdadır.
function CreateMutex(lpMutexAttributes: PSecurityAttributes; bInitialOwner: BOOL; lpName: PChar): THandle;
lpMutexAttributes: Muteksin güvenliği ile ilgli parametredir. Bu parametreye nil girerek varsayılan güvenlik özelliklerini ayarlamış oluyoruz.
bInitialOwner: Kanalın bu mutekse sahip olup olmadığını ya da yukarıda bahsettiğimiz gibi muteksin tetiklenip tetiklenmeyeceğini belirler. True ya da False giriyoruz. Genelde muteksi programın ana kanalında oluşturduğumuzdan, ana kanalın mutekse sahip olmasını istemeyiz. Bu yüzden genelde bu parametreye False gireriz.
lpName: Eğer farklı işlemler bu mutekse erişecekse bu muteksimize bir isim vermemiz gerekmektedir. Buraya nil de girebilirisiniz. Bu durumda isimsiz bir muteksimiz olur.
Bu fonksiyon eğer muteksi oluşturabilirse çıktı olarak muteksin handle numarasını dönderir. Eğer muteks oluşmamış ise 0 değerini çıktı olarak verir.
Muteksleri, kritik bölgeler gibi düşünebilirsiniz. Kritik bölge oluşturmak için kullandığımız InitializeCriticalSection fonksiyonu yerine CreateMutex fonksiyonunu, kritik bölgenin başlangıcını belirten EnterCriticalSection yerine WaitForSingleObject fonksiyonunu, kritik bölgenin bitişini bildiren LeaveCriticalSection fonksiyonu yerine de ReleaseMutex fonksiyonunu kullanıyoruz. CloseHandle ile de CreateMutex ile oluşan muteksin handle’ını kapatmayı da unutmuyoruz.
İlk önce bir muteks oluşturalım.
birmuteks := CreateMutex(nil, False, 'ornekmuteks');
Ardından kritik bölgeyi oluşturduğumuz yerlerdeki fonksiyonları muteksin fonksiyonları ile yer değiştiriyoruz. Şimdilik sadece Kanal1 için örnek verelim.
procedure Kanal1;
var
i: Integer;
begin
for i := 0 to 10 do
begin
WaitForSingleObject(birmuteks, INFINITE); //Muteksin tetiklenmesini bekle
SonucYazi := SonucYazi + 'd';
Sleep(10);
SonucYazi := SonucYazi + 'i';
SonucYazi := SonucYazi + 'y';
SonucYazi := SonucYazi + 'e';
Sleep(10);
SonucYazi := SonucYazi + 'z';
SonucYazi := SonucYazi + 'o';
SonucYazi := SonucYazi + 'n ';
Sleep(10);
ReleaseMutex(birmuteks); //Muteksi serbest bırak.
end;
end;Şimdi muteksin ne olduğuna dair kafanızda bir şeyler şekillenmeye başlmamıştır. Çünkü kodlara baktığımızda WaitForSingleObject fonksiyonu bir şeyleri bekliyor ve ReleaseMutex ise bir şeyi serbest bırakıyor. WaitForSingleObject, "tek bir nesne için bekle" gibi bir manası var. Esas yaptığı görev, birinci parametresinde verilen handle numarasına göre bir muteksi beklemektir. İkinci parametresinde ise ne kadar bekleyeceğini belirliyoruz. Bu örneğimizde INFINITE (sonsuz) girmekle, bir muteks tetiklenene kadar bekleyeceğini belirttik. Bu parametreye, en fazla ne kadar bekleneceğini milisaniye şeklinde girebilirsiniz.
Muteksi anlamada genelde verilen örnek ve bence en iyi örnek bayrak yarışıdır. Bayrak yarışlarında bir şeritte ancak bir koşucu koşabilir. Bayrağı alan koşmaya başlar. Bir şeritte, bayrağa sahip olmayan, koşabilmek için bayrağı beklemesi gerekmektedir. Böyelece her bir şeritte sadece bir yarışçı koşabilir.
Aynen bunun gibi, kanallar çalışabilmek için mutekse sahip olmaları gerekmektedir. Mutekse sahip olan koşmaya yani çalışmaya başlar. Mutekse sahip olmayan, muteksin kendisine gelmesini bekler. Bir hatırlatma olarak, önceki paragraflarda sahip olmanın tetiklemek olduğundan bahsetmiştik.
İşte WaitForSingleObject ile muteksin bu kanalımıza gelmesini beklemiş oluyoruz. Ve bunu örneğimizde, INFINTE yani sonsuz süre kadar bekliyoruz. Ve muteksle işimiz bittiğinde diğer kanalların kullanabilmesi için muteksi ReleaseMutex ile serbest bırakıyoruz. Ve yine tekrar ediyorum "Bir mutekse aynı anda sadece bir tek kanal sahip olabilir."
CreateMutex ile oluşturduğumuz muteksin handle’nı formun OnDestroy olayında CloseHandle ile kapatmayı da unutmuyoruz. Yani kritik bölgelerde yaptığımız DeleteCriticalSection yerine
CloseHandle(birmuteks);
gibi bir şey yazmalıyız.
Bu örneği, makaleyi fazla uzatmasın diye, burada tüm kodlarını yazmayacağım. Muteks örnek projesini buradan indirebilirsiniz.
Eğer tek bir muteks değil de bir den fazla muteksi tetiklemesini bekelemek istersek ne olacak? Bu durumda WaiıtForMultipleObjects fonksiyonunu kullanacağız. WaitForSingleObject tek bir muteksi beklerken WaitForMultipleObject fonksiyonu birden fazla muteksi beklemektedir. Kullanım aynı olduğu için bununla ilgili bir örnek yapmayacağım. Bu fonksiyon ile iligli tek söyleyebileceğim şey ikinci parametrede beklediğiniz mutekslerin handle’larını dizi şeklinde girmeniz olacaktır.
Başka İşlemlerden Mutekslere Sahip Olma
Dediğimiz gibi, mantık olarak mutekslerin kritik bölgelerden tek farkı, başka program ve işlemlerdeki kanallar ile ortak ve eş zamanlı çalışmaya izin vermesidir. Bunun için muteksimize bir isim vermemiz gerektiğini söylemiştik. İşte bu ismi kullanarak başka bir işlem muteksin handle numarasını alabilir. Gerisinde de WaitForSingleObject ve ReleaseMutex fonksiyonlarında bu handle numarasını kullanabiliriz. Yani mevcut bir muteksin handle numarasını alabilmek için:
birmuteks := OpenMutex(0, False, 'ornekmuteks');
dememiz yeterli. Bunu yukarıdaki örneğimizde CreateMutex yerine kullanabilirsiniz. Ama unutmamanınız gereken nokta bunun ile mevcut bir muteksin handle numarasını alırız. Eğer muteks CreateMutex ile hiç oluşturulmamış ise bu fonksiyon 0 değerini dönderir.
OpenMutex fonksiyonunun parametreleri CreateMutex ile aynı olduğundan burada fazladan bir açıklama yapmayacağım.
Bu konuda bir örnek yapmak isterseniz yukarıda verdiğimiz örneği iki uygulamaya bölebilirsiniz. Kanal1‘i birinci uygulamada, Kanal2‘yi de ikinci uygulamada oluşturursunuz. Ve ikisinde de OnCreate olayında şöyle bir şey girersiniz:
var
BirMuteks: THandle;
.....
procedure TForm1.OnCreate(....);
begin
BirMuteks := OpenMutex(0, False, 'ornekmuteks');
if BirMuteks = 0 then
BirMuteks := CreateMutex(nil, False, 'ornekmuteks');Kısaca burada yaptığımız işlem eğer "ornekmuteks" isminde bir mutex henüz oluşturulmamış ise oluşturuyoruz.
Bu şekilde iki veya daha fazla sayıda işlem tek bir muteks üzerinde kanallarını eş zamanlı olarak çalıştırabilirler. Bu örneği kendiniz yapmaya çalışın. Gerçi burada yapılmışı var
. Ama lütfen indirip incelemeden önce kendiniz yapmayı deneyin.
—
İşte size iki adet yöntem. Ve ikisi de windows programlamada çok sık kullanılmaktadır. Kanalları beraber çalıştırmak istediğinizde, istrer muteks kullanın isterseniz kritik bölge tanımlayın. Her ikisinin de tanımlanması ve kullanılması çok kolay. Kafanızdaki "kanal kullanmak çok zordur" düşüncesini birinci bölümde aştığınızı düşünüyorum. Buraya kadar olan kısım ile de "kanalları eş zamanlı çalıştırmak zordur" düşüncesini yendiğinizi zannediyorum.
Peki muteks ve kritik bölge arasında tercih yapmak gerekirse hangisini tercih etmeliyiz. Bence performans açısından pek fark olmaz. Seçim noktanız şu olmalı. Eğer, tek bir işlemden değil de bir çok işlemden yani bir çok programdan oluşan bir gurubun kanalları ortak ve eş zamanlı kullanmasını düşünüyorsak kesinlikle muteks kullanmalıyız. Aksi durumda yani eş zamanlı çalışacak olan kanallar sadece tek bir işlemde bulunuyorlarsa o zaman seçim size kalmış. Hangisi rahatınıza gidiyorsa onu kullanabilirsiniz.
Şimdi farklı bir konuya geçiş yapalım. Hazırsanız ikinci sayfadan devem edelim.
Sayfalar: 1 2
» Tags:



Fatihcim tek kelimeyle mükemmel eline beynine sağlık. Bu mübarek gün böyle paha biçilmez dökümanlar hazırladığın için çok teşekkür ederim…
Sağolun Hüseyin hocam. Faydalı olduysa ne mutlu…
makale için çok teşekkürler öğrenmek istediğim bir husus var database örneğinizi inceledim fakat ben bu işi ib bileşenleri yapmak istiyorum 2 adet select çalıştırmak istiyorum
Teşekkür ederim. Çok önemli bir konuyu ele almışsınız ve kaliteli bir anlatımınız var. Tekrar teşekkür ederek naçizane bir istekte bulunmak istiyorum. TThread kullanımı ile ilgili de bir makale yazabilir misiniz?
İkinci sayfayı görmemişim. Özür dilerim. Daldım gittim ben kodlara
2 tane query üzerinde 1000000 kayıtta select denedim aşağıdaki şekilde çalıştırdım fakat VCL ile hiç bir netice alamadım ib bileşenleri üzerinde firebird databasende çalışma yaptım. Birde üstad VCL ile ib datasetleri üzerinde bir örnek verirsen sevinirim ben vcl de hiç bir netice alamadım…
procedure Sorgu1;
procedure Sorgu2;
var
Form1: TForm1;
BirinciKritikBolge: TRTLCriticalSection; //kritik bölgemizi temsil ediyor.
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
// BirinciQuery:TSorguKanali;
Kanal1ID:DWord;
begin
// BirinciQuery := TSorguKanali.Create(TIbDataset(IBQuery1), Datasource1);
CreateThread(nil, 0, @Sorgu1, nil, 0, Kanal1ID);
ShowMessage('1');
end;
procedure TForm1.Button2Click(Sender: TObject);
var
// IkinciQuery:TSorguKanali;
Kanal2ID:DWord;
begin
// IkinciQuery := TSorguKanali.Create(TIbDataset(IBQuery2), Datasource2);
CreateThread(nil, 0, @Sorgu2, nil, 0, Kanal2ID);
ShowMessage('2');
end;
procedure Sorgu1;
begin
EnterCriticalSection(BirinciKritikBolge); //BirinciKritikBolge başlangıcı
Form1.IBQuery1.Open;
Form1.DataSource1.DataSet := Form1.IBQuery1;
Form1.IBQuery1.FetchAll;
LeaveCriticalSection(BirinciKritikBolge); //BirinciKritikBolge bitişi
end;
procedure Sorgu2;
begin
EnterCriticalSection(BirinciKritikBolge); //BirinciKritikBolge başlangıcı
Form1.IBQuery2.Open;
Form1.DataSource2.DataSet := Form1.IBQuery2;
Form1.IBQuery2.FetchAll;
LeaveCriticalSection(BirinciKritikBolge); //BirinciKritikBolge bitişi
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
InitializeCriticalSection(BirinciKritikBolge);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
DeleteCriticalSection(BirinciKritikBolge);
end;
end.
Üstad aşağıda şekilde ib bileşenlerinden netice aldım fakat VCL ile ib bileşenlerinde neticeye ulaşamadım VCL ile IB bileşenlerine örnek verebilirsen sevinirim. Ben 1000000 kayıt üzerine 2 query ile bağlanarak test yaptım…
procedure Sorgu1;
procedure Sorgu2;
var
Form1: TForm1;
BirinciKritikBolge: TRTLCriticalSection; //kritik bölgemizi temsil ediyor.
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
// BirinciQuery:TSorguKanali;
Kanal1ID:DWord;
begin
// BirinciQuery := TSorguKanali.Create(TIbDataset(IBQuery1), Datasource1);
CreateThread(nil, 0, @Sorgu1, nil, 0, Kanal1ID);
ShowMessage('1');
end;
procedure TForm1.Button2Click(Sender: TObject);
var
// IkinciQuery:TSorguKanali;
Kanal2ID:DWord;
begin
// IkinciQuery := TSorguKanali.Create(TIbDataset(IBQuery2), Datasource2);
CreateThread(nil, 0, @Sorgu2, nil, 0, Kanal2ID);
ShowMessage('2');
end;
procedure Sorgu1;
begin
EnterCriticalSection(BirinciKritikBolge); //BirinciKritikBolge başlangıcı
Form1.IBQuery1.Open;
// Form1.DataSource1.DataSet := Form1.IBQuery1;
Form1.IBQuery1.FetchAll;
LeaveCriticalSection(BirinciKritikBolge); //BirinciKritikBolge bitişi
end;
procedure Sorgu2;
begin
EnterCriticalSection(BirinciKritikBolge); //BirinciKritikBolge başlangıcı
Form1.IBQuery2.Open;
// Form1.DataSource2.DataSet := Form1.IBQuery2;
Form1.IBQuery2.FetchAll;
LeaveCriticalSection(BirinciKritikBolge); //BirinciKritikBolge bitişi
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
InitializeCriticalSection(BirinciKritikBolge);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
DeleteCriticalSection(BirinciKritikBolge);
end;
end.[/delphi]
firebird üzerinde 2 adet SQL çalıştırmaya çalıştım toplam 1000000 adet kayıt vardı tabloda aynı anda ne yaptıysam çalışmadı…
Hocam thread ile ilgili olarak yazdığınız makaleden ötürü çok teşekkür ederim. Çok faydalı, açıklaycı bir makale olmuş elinize sağlık.
Thread ile ilgili aradığım kaynak buydu. Emeğinize sağlık….
Gerçekten güzel bir makale olmuş okuduk uyguladık öğrendik.
Bi ara da uygun düşüp Stream ‘lerden derinlemesine makale yazılsa ne güzel olur.
on numara makale çok sağolun.
Makale cok guzel olmuş,
Windows işletim sistemini anlamak için gerekli bir konu.
Bir kanal sadece yazma işlemi, bir kanal da sadece okuma işlemi yapıyor olsa da TRTLCriticalSection kullanmak gerekir mi?
> @SimaWB yazmış:
> Bir kanal sadece yazma işlemi, bir kanal da sadece okuma işlemi yapıyor olsa da TRTLCriticalSection kullanmak gerekir mi?
Bu duruma göre değişir. Eğer kritik bölge kullanmanız gerekiyorsa bunu tanımlamalısınız. Mesela okuma ve yazma işlemlerinizde tekillik olması söz konusu ise yani, aynı anda aynı veriye yazma işlemi yapılması hata meydana getirecekse kritik bölge tanımlamalısınız.
kardeş formun üzerine yerleştirdigim TEmbeddedWB component le işlem yapacagım ama adres okunamadı falan diyor anlamadım hatayı.
paylaşım için teşekkürler
güzel ve anlaşılır bir makale hazırlamışsınız
çok sağolun
balustrady systemowe
program do wystawiania faktur