> Delphi > Delphi ile Thread(Kanal) Kullanımı – Bölüm 2

Delphi ile Thread(Kanal) Kullanımı – Bölüm 2

VCL ve Kanallar

VCL kütüphanesini normalde tamamen kanal uyumlu değildir. Daha doğrusu bir kaç önemli şey dışında VCL, kanal uyumlu olarak geliştirilmemiştir. Böyle olmasının sebebi, tamamen performans ile ilgilidir. Eğer VCL tamamen kanal uyumlu olsaydı çok yavaş çalışırdı. Ama şu an VCL kütüphanesindeki bileşenler gerçekten hızlıdır. Eğer VCL tamamen kanal uyumlu yapılsa idi bir çok yerde kritik bölge ve muteksler oluşturulacaktı. Bu kritik bölge ve mutekslerin sayısı o kadar çok olacaktı ki VCL’in performansı farkedilir derece düşecekti. Bu yüzden VCL’e kanal uyumluluğu katmak programcının sorumluluğuna bırakılmıştır.

VCL’de bulunan ve genelde TControl‘den türeyen görülebilen bileşenleri kanallar ile kullanmaya kalkmak çoğu kez çökmelere ve şişmelere sebep olacaktır. Buraya kadar öğrendiğimiz teknikler ile VCL bileşenlerini, özellikle görülebilen bileşenleri kullanmaya kalktığınızda hemen kendini belli etmese bile eninde sonunda sorunlar çıkaracaktır.

Bu yüzden VCL ile kanalları kullanabilmek için yine VCL içinden bir çaremiz bulunmakta. Bu çare TThread sınıfıdır.

Eğer birinci bölümün başlarını hatırlarsanız bir uyarıda bulunmuştum. Bu uyarıyı bir daha hatırlatıyorum. Eğer yapacağınız işlemler VCL’i kullanmayı gerektiriyorsa, daha doğrusu TComponent‘in alt sınıfındaki bileşenleri kullanmayı gerektiriyorsa TThread sınıfını kullanmamız gerekmetedir. Bunun nedenini ileriki konularda söyleyeceğimizi yazmıştık. İşte bunun nedenini bu başlığın ilk paragraflarında bahsettik ve şimdi de bahsetmeye devam ediyoruz.

Peki TThread sınıf ne yapıyor? TThread sınıfı bize kanallardan VCL çağrımları yapabilmek için Sycnhronize metodunu sağlıyor. En büyük avanatajı da budur.

VCL kütüphanesi, özellikle TComponent’in alt sınıfları programın ana kanalının bir parçası olmak üzere geliştirilmişlerdir. Bu yüzden VCL’i kanallardan kullanmak genelde felaketler ile sonuçlanmıştır (üff çok mu ağır oldu ne 😉 ). Synchronize metodunun getirdiği çözüm ise çok basittir. Bir an için mevcut kanalın işlemesini durduruyor ve bu metod ile yapacağımız işlemleri ana kanalın bir parçası haline getiriyor. Bu işlemler bittiğinde ise mecut kanal işine devam ediyor. Böylece bu metod ile VCL’i, ana kanal ile eş zamanlı olarak başka kanallardan kullanabiliyoruz. Bu yüzdendirki bu metodun ismi Synchronize olmuştur, yani anakanal ile "eş zamanlı yap".

Kısacası, VCL’e ulaşabilmek için işlemlerimiz ana kanalın bir parçası olmak durumunda. VCL’e ulaşmadığımız zamanlarda ise eş zamanlı çalışmadan normal kanal yapısına dönmeliyiz. İşte bütün bu işlemleri Synchronize metodu sizin yerinize gerçekleştirmektedir.

Dedik ki genelde TComponent‘in alt sınıfları kanal uyumlu değildir bu yüzden TThread kullanmalısınız. Bununla birlikte bazı TComponent’den türemeyen sınıflar rahat bir şekilde kanal kullanılabilir. Bunlardan bazıları şunlardır. TStream‘den türeyen sınıflar, TStrings‘den türeyen sınıflar, TList sınıfı, TComponent‘in kendisi, vs..

Evet TComponent’in kendisini de kanallarla beraber kullanabilirsiniz. Bunun bize sağlayacağı şöyle bir fayda vardır. TThread nesnesini kullanmak yerine, tamamen kanal uyumlu bileşen yapabilirsiniz. Tabi gerçekten ne yaptığınızı biliyorsanız ortaya tamamen kanal uyumlu ve TComponent’den türemiş bileşenler oluşturabilirsiniz. Bunun için nerelerde kritik bölge ve muteks oluşturacağınızı iyi bilmelisiniz. Yani kanal uyumlu bir bileşen yapmanın yolu kritik bölgeleri ve muteksleri akıllıca kullanmaktan geçer. Bu şekilde bileşenlerinizi tam kanal uyumlu yapabilirsiniz. Her neyse… Bu paragraf daha çok bileşen yazarlarını ilgilendiriyor.

Şimdi TThread nesnesinin kullanımını basit ve soyut bir örnek ile görüp geçeceğiz ve ardından gerçekte en çok karşılaşılan problemlerden, kanal uyumlu veritabanı erişimi ile iligli bir örnek daha yapacağız.

TThread Nesnesinin Kullanımı

Yapacağımız işlem çok basit olacak. Sadece TThread nasıl kullanılır bunu inceleyeceğiz. Bunun için ilk başta yeni bir uygulama açalım ve forma bir adet progressbar ekleyelim. Progressbar bileşeninin Step özelliğine 1 değerini verelim. Ardından bir adet button yerleştirelim ve Caption özelliğini "Kanalı çalıştır" şeklinde değiştirelim.

File / New menüsünden "Other…" seçeneğini seçelim. "Delphi Files" sekmesinden "Thread Object"’i bulup çift tıklayalım. Eğer sizin Delphi sürümünüzde böyle bir seçenek yok ise siz yeni bir unit oluşturun ve birazdan vereceğimiz kodları direk olarak yapıştırın ve kaydedin. Eğer varsa, karşınıza TThread nesnesinden türeyecek olan bir sınıf ismi soracaktır. Bu örneğimiz için "Class Name" olarak TBirDonguKanali yazalım ve entere basalım. Ve sonrasında açılan uniti aşağıdaki gibi değiştirelim:



		

Buradaki "Unit1", formumuzun uniti. Şimdi de formdaki düğmemizin OnClick olayına şunları yazalım:



		

Tabiki TBirDonguKanali sınıfını kullanabilmek için formun bulunduğu unitin uses kısmına thread’in untini eklemeliyiz.

Şimdi bu programı derleyelim ve çalıştıralım. Düğmeye basmadan önce her zamanki gibi açık değilse "Thread Status" ve "Event Log" pencerelerini görebileceğimiz bir yere koyalım.. Ardından düğmeye basalım ve olanları gözlemleyelim.

Aslında yaptığımız basit bir kanal tanımlamasından başka bir şey olmadı. Fakat bir noktada çok farklı bir çağırım yaptık. O da Synchronize çağrısıdır. Synchronize metodu, bir adet parametre almaktadır. Bu parametre, programın ana kanalı ile eş zamanlı çalıştıracağımız işlemleri içieren bir prosedür olacaktır. Bu prosedür parametresiz ve bir sınıfın nesnesi olmak zorundadır. Bu örneğimizde ProgressGuncelle metodu bu işi görmektedir. Bu yüzden Synchronize metodu ile bu metodumuzu eş zamanlı yaptık. Yine hatırlatmak gerekirse Sleep runtinin kodları yavaşlatmak için kullandık. Aksi durumda işlemler çok hızlı olur ve ne olup ne bitiyor göremeyiz. Ama siz kendi programlarınızda bunu kullanmak zorunda değilsiniz.

Burada bir karara vardık. ProgressBar’ın adımı artırılacak ve ekrana tekrar çizilerek güncelenecek. Bu işi yapan StepIt metodunu çağırmamız gerekir. İşte bu durumda aldığımız karara göre bu metodu Synchronize ile eş zamanlı hale getirmemiz gerklidir. Çünkü VCL’e ait ProgressBar bileşenine burada müdahale ediyoruz.

Gördüğünüz gibi Execute metodunu TThread‘den miras alıp üzerine yazıyoruz. Ve içerisine kanal çalıştırıldıktan sonra yapılacak kodları yazıyoruz. Ardından VCL kullanılan kısımları belirleyip Synchronize ile sarmalıyoruz.

Kanalımızı düğmenin OnClick olayın oluştururken şöyle bir şey yazmıştık.



		

Burada TThread sınıfı bir adet parametre alıyor. Bu parametreye False girdiğimizde kanal oluşturulur oluşturulmaz çalışmaya yani Execute metodu çağrılmaya başlanacaktır. Eğer buraya True girerseniz, kanal hemen çalıştırılmayacak ve sizin Resume metodunu çağırmanızı bekleyecektir. Yani:



		

Olaki kanalı durdurmak istediniz. Bu durumda aşağıdaki metodu çağırıyoruz.



		

Kanal ister Terminate metodu ile sonlansın, isterse kendi kendine sonlansın, TThread‘e ait OnTerminate olayı tetiklenecektir. Yani kanal işini bitirir bitirmez bir şeyler yapmak istiyorsanız şöyle bir şeyler yapmalısınız.



		

gibi…

Bu basit bir örnekti. Ama TThread‘in çalışma mantığını anlamak için iyi bir örnekti diye düşünüyorum. Şimdi biraz gerçek hayattan örnek verelim.

Kanal Uyumlu Veritabanı Kullanımı

Burada bilmeniz ve aklınıza kazımanız gereken nokta şudur. Her veritabanı kütüphanesi thread-safe yani kanal uyumlu değildir. Bunu internette hangisinin thread-safe olup olmadığını araştırarak bulabilirsiniz.

Delphi 6 yeni çıktığı sıralarda veritabanı ve kanalların birlikte kullanılması noktasında bir çalışmam olmamıştı. Ve Delphi 6’dan sonra DBExpress, Delphi’cilerin gözdesi olmaya başlamıştı. Ben de nedenini merak etmiştim. Çünkü BDE varken ve kullanımı kolayken neden DBExpress kullanılır ki? Tabi iş öyle basit olmadığını sonraları gördüm. Delphi 6 ile beraber sadece DBExpress sürücüleri thread-safe yani kanal uyumlu olmuştu. Delphi 7 ile beraber DBExpress bileşenleri ile beraber tamamen kanal uyumlu olmuştur.

IBX bileşenleri de thread-safe yani kanal uyumludur. Bu yüzden bu iki veritabanını rahat bir şekilde bu bölümün başlarında anlattığımız gibi kritik bölge ve muteksler içinde kullanabilirsiniz.

Ama BDE yani Borland Database Engine ise thread-safe değildir. Hem sürücüleri hem de bileşenleri thread-safe değildir. Yani TDatabase, TQuery, TTable bileşenleri kanal uyumlu değildir.

Demek ki veritabanları için sadece bileşenlerin kanal uyumlu olması yetmiyormuş. Veritabanı sürücüleri de kanal uyumlu olmalı imiş.

Piyasada bir çok veritabanı ve bir çok veritabanı bileşeni mevcut. Burada kalkıp hepsini teker teker burada tartışmamız biraz zor olur. Bu yüzden burada sadece BDE üzerine örnek vermek istiyorum. Zira BDE bileşenleri kanal uyumlu olmadığından kanallar, programcıları en çok BDE bileşenlerinde zora sokmakatadır.

BDE kanal uyumlu değildir, fakat TSession bileşeni ile kanal uyumlu hale getirilebilir. TSession ile her farklı işleminiz için farklı bir oturum açarsınız. Fakat dikkat edilmesi gereken bir kaç nokta var.

Birincisi, her bir sorgu için ilişkilendirilmiş bir oturum olmalıdır. Bu ilişkilendirme dataset bileşeninde(TQuery, TTable, vs..) bulunan SessionName özelliği ile yapılır. Aynı şekilde TDatabase kullanıyorsanız her bir TSession için ayrı ayrı TDatabase bulunmalıdır.

İkincisi, bir dataset bileşeni kullanıldığı kanalda bir DataSource’a bağlanamaz. Bunu yapabilmek için TThread‘de bulunan Synchronize metodunu kullanmalısınız ya da bu bağlama işlemini ana kanalda yapmalısınız.

Bu iki noktaya dikkat ettiğiniz sürece BDE ile sorununuz olacağını zannetmiyorum.

Genelde BDE’nin thread-safe olmadığı bilinmiyor veya unutuluyor ve ayrı ayrı kanallarda SQL cümlecikleri çalıştırılmaya kalkılıyor. Halbuki BDE ve bileşenleri bunu desteklemezler. Kısaca bir daha vurgulamak istiyorum. Birincisi, her kanal için bir TSession ayarlamalıyız ve kanallarda kullanılacak olan her dataset bileşeni için kanala ait TSession‘nı, SessionName özelliği ile atamalıyız. İkincisi, dataset bileşenlerini hiç bir DataSource nesnesine bağlanmadığından emin olmalısınız. Çünkü bu bağlama işlemi Synchronize ile yapılmalıdır.

Şimdi bununla iligli bir örnek yapalım. Uygulamamızda aynı anda iki adet sorgu çalıştırılsın ve sonucu ekranda göstersin.

Yeni bir uygulama açalım ve form üzerine iki adet DBGrid, bir adet DataSource, iki adet TQuery, iki adet TSession ve bir adet button koyalım. İki adet dbgridin DataSource özelliğini eklediğimiz DataSource olarak belirleyelim. Query bileşenlerinin DatabaseName özelliğini DBDEMOS yapalım. Ve birinci query bileşenine aşağıdaki sql kodunu yazalım.



		

İkincisine de aşağıdaki sql cümleciğini yazalım



		

İlk başta oturum bilgilerini ayarlayalım. Bunun için iki adet eklediğimiz TSession bileşenlerinden birincisinin SessionName özelliğine "Oturum1" diğerine de "Oturum2" diyelim. Ardından iki adet eklediğimiz query bileşenlerinden birincisinin SessionName özelliğini Oturum1, diğerini de Oturum2 olarak ayarlayalım.

Böylece bahsettiğimiz uyarılardan birincisini halletmiş olduk. Şimdi ikinci uyarıyı hatırlıyoruz. Asla bu dataset bileşenlerine yani bu örneğimizdeki query bileşenlerine DataSource atamıyoruz. Çünkü bunlar Synchronize ile bağlanması icab ediyor.

Şimdi ikinci uyarı eşliğinde bir kanal oluşturalım. Ya kendiniz elinizle oluşturun ya da bir önceki örnekte anlattığımız gibi File / New menüsünden "Thread Object" ile bir TThread kanalı oluşturun. TThread sınıfımıza TSorguKanali ismini verelim. Bu sınıfın gövdesini aşağıdaki gibi düzenleyelim.



		

Gördüğünüz gibi bir constructor tanımladık. Çünkü bu kanalımız hangi datasete hangi datasource’un bağlanacağını bilmesi şart. Şimdi ise bu sınıfın kod tanımlamalarını verelim.



		

İlk başta Create constructor’ına bakalım. inherited ile ata sınıfımız olan TThread‘in Create‘ini çağırıyoruz. Tabi burada True parametresi ile çağırıyoruz. Yani kanalımız oluşturulur oluşturulmaz çalışmaya başlamayacak! Bizim Resume metodunu kullanmamızı bekleyecek. Çünkü şimdi çalışmaya başlarsa FDataSource ve FDataSet değişkenleri atanmamış bir şekilde Execute metodu çalıştırılacak. Bu da FDataSet ve FDataSource tanımlı olmadığından hataya sebep olacaktır. Bu yüzden kanal durgun bir vaziyette oluşturuluyor. Ardından FDataSource ve FDataSet değişkenlerine gelen parametreleri atıyoruz. Böylece artık Execute metodunu çalıştırabiliriz. Bunun için durmuş durumda olan kanalımızı Resume ile çalıştırmaya başlıyoruz.



		

Execute metodumuzda DataSource bağlama işlemini yapıyoruz. İlk başta DataSet bileşenimizi açıyoruz. DataSet bileşenine bir session atadığımızdan rahatlıkla Open ile query’de yazdığımız sorgu çalıştırlabilir. Ama DataSource bağlı olmadığında şu an dbgridlerde bir şey gösterilmez.

Ardından dbgridlerde veya datasource’a bağlı hangi db bileşenleri varsa onları harekete geçirip formda birşeyler göstermesini sağlamak için DataSet bileşenimize DataSource bileşenini bağlamalıyız. Uyarılardan ikincisini hatırlarsanız bu bağlama işlemi Synchronize ile yapılmalı. Bu yüzden burada Synchronize ile bağlama işini yapan metodumuzu çağırıyoruz.

Sonrasında gelen kodlar bir sql hatası olması durumunda hatanın gösterilebilmesi içindir. İşte burada da hatayı gösterirken Synchronize kullanmalıyız. Çünkü ekranda gösterilecek olan mesaj VCL’in görsel kısmı ile ilgilidir ve Synchronize yapılmalıdır.



		

Bu iki metod, Synchronize yaptığımız metodlardır. Birincisinde DataSet bileşenimize DataSource’u bağlıyoruz. İkincisinde ise ekranda hata mesajını gösteriyoruz.

Kanalımız hazır durumda. Dilerseniz şimdi bu kanalı kullanarak formumuzdaki query’leri kanallarda çalıştıralım. Bunun için formumuza geri dönelim ve Button’un OnClick olayına şu kodları yerleştirelim.



		

Programı çalıştırdığınızda iki adet sorgunun aynı anda(kullanıcıya göre) çalıştırıldığını göreceksiniz.

Bu örnekten çıkarmamız gereken en büyük sonuç, Synchronize çağırımının yapılacağı yer ve zamanları iyi tespit edebilmektir. Bu çağırımın nerelerde kullanılacağını bildiğiniz taktirde hiç bir sorunla karşılaşacağınızı zannetmiyorum.

Şahsen genelde VCL’in görünüm ile ilgili kısımlarında ve TComponent’de türeyen ve thread-safe olmadığını bildiğim bileşenler için Synchronize kullanıyorum.

Buraya kadar geldi iseniz, kanallar noktasında çok fazla yol katettiniz demektir. Aslında makaleyi burada bitirebiliriz. Ama fazladan bir kaç küçük konuya daha değinmek istiyorum.

Kanalların Önceliğini Ayarlamak

Kanalların önceliğinin, kanalın çalışma süresini etkilediğini biliyoruz. Bir kanalın önceliğini belirlemek için SetThreadPriority fonksiyonunu kullanıyoruz. Kanalın önceliğini öğrenmek için ise GetThreadPriority kullanılır.

Kanalların, işlemler içinde bulunduğunu biliyoruz. Bir kanala bir öncelik atamanız o işlem için geçerli olacaktır. Daha doğrusu kanalın içinde bulunduğu işlemin önceliği direk olarak kanalın önceliğini de etkilemektedir. Bu durumda iki adet öncelik kavramı ortaya çıkıyor. Birincisi işlemin önceliği ikincisi kanalın önceliğidir.

Eğer işlem önceliğiniz çok yüksek ise, işlemin içinde bulunan tüm kanalların öncelikleri de o ölçüde yüksek olur. Bir işlemin önceliğini belirlemek için ise SetPriorityClass fonksiyonunu kullanıyoruz. Aynı şekilde GetPriorityClass ile de işlemin mevcut önceliğini öğrenebiliriz.

Bir kanala vereceğiniz öncelik değerleri THREAD_PRIORITY ile başlar. SDK yardım dosyalarından tüm listeyi bulabilirsiniz. Ya da Delphi editöründe THREAD_PRIORITY yazıp ctrl+boşluk yapabilirsiniz. SetThreadPriority aşağıdaki gibi tanımlanmıştır.



		

İlk parametreye önceliğini belirlemek istediğimiz kanalın handle numarasını giriyoruz. İkinci parametrede ise THREAD_PRIORTY ile başlayan seçeneklerden birini giriyoruz. Mesela aşağıdaki örnek, kanalımızı idle yani hiç bir işlem yapılmazken çalıştırmaya başlayacaktır. Ayrıca idle, en düşük önceliği ifade eder.



		

gibi…

Kanalları Durdurmak ve Öldürmek

Aslında bu konudan bahsettik. Kanalları durdurmak için ResumeThread fonksiyonu kullanılır. Öldürmek için ise TerminateThread ile hafızadan silinir. Ama bununla ilgili bir örnek yapmamıştık. Aşağıda bir kanal durgun halde başlatılıyor, sonra çalıştırılıyor ve hemen ardından durduruluyor. En sonda ise hafızdan siliniyor.



		

Aynı şeyi TThread ile yapalım.



		

Sonuç

Gördüğünüz gibi kanallarla uğraşmak o kadar da zor bir hadise değil. Sadece neyin nerede kullanılacağını iyi bilmeilisiniz. Kanallar hakkında "kanal kullanmak ustaların işidir, bize gelmez" gibi bir ön yargıyı kafanızdan attığınızı düşünüyorum. Zira artık windows’un ileri seviye konularından olan kanal oluşturma, kritik bölge tanımlama ve muteks kullanımını gördünüz.

Belki de dikkat etmeniz gereken tek nokta VCL konusu. Ama burada bahsettiğiimiz gibi her ne kadar VCL kanal uyumlu olmasa da TThread gibi bir çözümü de bulunmakta. Bundan sonrası size kalmış. Şimdi üşenmeyin ve programlarınızı kanal uyumlu yapın. Kanalları ne kadar çok kullanırsanız, o kadar çok alışırsınız.

Her zamanki gibi yorum ve eleştirileriniz bekliyorum. Sorularınız olduğunda buradan ya da delphiturkiye forumlarından iletebilirsiniz.

Fatih Tolga Ata © 2007

Kaynaklar

  • Windows SDK Yardım Dosyaları
  • CodeGear Rad Studio Yardım Dosyaları
  • Classes.pas Dosyası
  • Delphi 4 Unleashed, Charlie Calvert, Sams Pub., 1999
  • borland.delphi.* haber gurupları

Sayfalar: 1 2

» Tags: , , ,

22 Comments

  • At 2007.10.06 23:55, Hüseyin ÖZDEMİR said:

    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…

    • At 2007.10.07 00:30, Fatih Tolga Ata said:

      Sağolun Hüseyin hocam. Faydalı olduysa ne mutlu…

      • At 2007.10.09 22:22, hasan polat said:

        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

        • At 2007.10.09 23:32, hüseyin yıldırım said:

          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?

          • At 2007.10.09 23:34, hüseyin yıldırım said:

            İkinci sayfayı görmemişim. Özür dilerim. Daldım gittim ben kodlara

            • At 2007.10.11 03:29, Hüseyin ÖZDEMİR said:

              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.

              • At 2007.10.11 03:34, Hüseyin ÖZDEMİR said:

                Ü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]

                • At 2007.10.12 03:50, Hüseyin ÖZDEMİR said:

                  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ı…

                  • At 2008.01.24 11:13, noname said:

                    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.

                    • At 2008.01.25 13:58, Ertan ÖZTÜRK said:

                      Thread ile ilgili aradığım kaynak buydu. Emeğinize sağlık….

                      • At 2008.09.06 11:58, özkan danaci said:

                        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.

                        • At 2008.09.19 15:57, Kenan Karagöz said:

                          on numara makale çok sağolun.

                          • At 2008.10.06 23:27, Mustafa Sağat said:

                            Makale cok guzel olmuş,
                            Windows işletim sistemini anlamak için gerekli bir konu.

                            • At 2009.01.30 14:19, SimaWB said:

                              Bir kanal sadece yazma işlemi, bir kanal da sadece okuma işlemi yapıyor olsa da TRTLCriticalSection kullanmak gerekir mi?

                              • At 2009.02.17 01:12, Fatih Tolga Ata said:

                                > @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.

                                • At 2010.05.05 10:11, Anonim said:

                                  kardeş formun üzerine yerleştirdigim TEmbeddedWB component le işlem yapacagım ama adres okunamadı falan diyor anlamadım hatayı.

                                  • At 2010.07.20 11:52, yusuf şimşek said:

                                    paylaşım için teşekkürler

                                    güzel ve anlaşılır bir makale hazırlamışsınız

                                    çok sağolun

                                    • At 2012.07.12 05:03, Lepkneend said:

                                      • At 2012.09.13 16:54, Nazim Keskin said:

                                        MErhaba
                                        faydalı bir makale olmuş. buradan da çok şey öğrendim.çok teşekkürler.
                                        bir programım var thread kullandım.
                                        birde problemim var. program kapanmadan sürekli çalışmak zorunda ve sürekli data okuyor. milyonlarca kez thread çalışıyor. threadler işi bitince terminate ediliyor ve program bir süre sonra hata verip kapanıyor.

                                        task manager da programı izleyince handle sütunu sürekli artıyor ve 500ya da 600bini gecince programın kapandığını fark ettim. bir çözüm yolu bilen var mı?

                                        ( not: her thread çalıştırdığımda karşılığında handle sütunu 2 adet artıyır. en fazla aynı anda 10 thread çalışıyor. 2 handle dan biri thread teminate den sonra eksiliyor. yani her thread çalışmasından sonra 1 adet handle artıyor vebir süre sonra hata veriyor ) çok kötü anlatmadım inşallah anlaşılıyordur.
                                        İyi çalışmalar
                                        Nazım

                                        • At 2013.01.21 18:52, CodeFirst said:

                                          hocam merhabalar saygılar öncelikle çok teşekkür ederim bir sorum olacak;

                                          Kanalların, işlemler içinde bulunduğunu biliyoruz. Bir kanala bir öncelik atamanız o işlem için geçerli olacaktır. Daha doğrusu kanalın içinde bulunduğu işlemin önceliği direk olarak kanalın önceliğini de etkilemektedir. Bu durumda iki adet öncelik kavramı ortaya çıkıyor. Birincisi işlemin önceliği ikincisi kanalın önceliğidir.

                                          burada işlem, işlem önceliği gibi açıklamalar gördüm fakat kanal kavramını anlamama rağmen işlem derken neyi kasıt ettiniz.

                                          Bir işlemin önceliğini belirlemek için ise SetPriorityClass fonksiyonunu kullanıyoruz // bu fonksiyondan da ne demek istediğimi belki daha iyi anlayabilirsiniz hocam

                                          • At 2013.02.18 12:18, Namiq said:

                                            Salam Fatih bəy.
                                            Çox sağ olun!
                                            Təşəkkürlər edirəm bu gözəl məntiqli anlaşıqlı məqalələrin üçün!
                                            Mən Kanallardan TCPServer/Client və COM port ilə bir yerdə işlədilməsində istifadə edirəm. Mənim çətinliyim TCP ilə msg göndərərkən Connect/Disconnect edirəm. Msg göndərilməsi tez tez olarsa Already Connect bildiri mesajı verir. Bir də ki, internet kəsilərsə bir müddətdən sonra TCP component bağlanırmış kimi, Connect yaranmır.
                                            Bu mövzüdə köməyiniz olarsa Minnətdar olaram!

                                            • At 2013.05.29 11:52, huseyin said:

                                              selamun aleykum.
                                              hocam öncelikle selamlar ve teşekkürler. en son 2009 da cavap yazmışsınız. umarım bu son mesajlar size ulaşıyordur.
                                              bunun yanı sıra diğer arkadaşlardan yardımcı olabilecek varsa da sevinirim.

                                              durum şudur ki, seri port üzerinden bir cihaz ile haberleşiyorum. bunun için bir activex bileşenim var, içinde cihaz ile haberleşmeyi sağlayan hazır fonksiyonlar tanımlı.
                                              bu haberleşme işlemi sık sık yapıldığı için program aşırı yavaşlıyor. ben de haberleşme rutinlerini kanal içerisinde kullanmaya çalıştım ama beceremedim.
                                              anladığım kadarı ile kanal fonksiyonunun içinden başka bir fonksiyon çağırımı yapılamıyor, doğru mudur ?

                                              çünkü; çalışan bir kanal fonksiyonuna basit bir showmessage(‘ buradayım’) komutunu bile koysam, bellek read olamadı falan diyor.
                                              kanal fonksiyonu içinden başka fonksiyonlar çağırılabilir mi, çağırılabilirse nasıl ?

                                              VCL yi mi incelemem gerek daha fazla ?

                                              (Required)
                                              (Required, will not be published)