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

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

Yaptığımız projelerin bir bölümü eninde sonunda bu konuya dayanıyor. Genelde kanal gerekli olduğu halde Timer ya da Application.ProcessMessages gibi çarelere gitmeye çalışıyoruz Ve devamında hem görsel hem de işleyiş açısından istemediğimiz sonuçlarla karşılaşıyoruz. Halbuki kanalların kullanılması sanıldığı kadar zor değildir. Bu ön yargıyı bu makalede aşmaya çalışacağız.

Bu makale, ileri seviye Windows programcılığına geçiş kapısıdır. Bu makeledeki konuları öğrendikten sonra Win32 programcılığının en güçlü özelliklerini öğrenmiş olacaksınız.

Yanlız "ileri seviye" tabiri gözünüzü korkutmasın. Çünkü makeleyi bitirdiğinizde thread kullanımının aslında ne kadar kolay olduğunu göreceksiniz. Bununla birlikte bu makalede bu konu ile ilgili her ayrıntıyı anlatabilmemiz için yüzlerce sayfalık kitap yazmamız gereklidir. Bu yüzden burada işin mantığını kapıp, ihtiyacınız oldukça yardım dosyalarına müracaat etmeniz gerekebilir.

Kanallar hakkında hiç bir bilginiz olmayabilir. Bu makalede işin temelinden alacağız ve makaleyi bitirdiğinizde kendi programlarınıza kanal ekleyebilecek duruma geleceğinize inanıyorum.

Bu makale serisinde kanallar temelden anlatılmakla beraber, ileri seviye kanal kullanımı, VCL bileşenlerinde kanal kullanımı ve Muteksler de ana konularımız arasına girecektir.

Giriş

İlk başta bir kaç teorik bilgi ile başlamak istiyorum. Bu bilgilieri olabildiğince sıkmadan, kısa tutmaya çalışacağım.

Disk üzerindeki her bir dosya çalıştırıldığında artık windows için birer işlem(process) olurlar. Bir işlem Windows için fazla bir şey ifade etmez. Çünkü işlemler sadece hafızada belli bir bölgede var olmaktan sorumludur. Esas işlemi yapan kısım kanallardır(thread). Bir işlem en az bir adet kanala sahiptir. Win 3.1 gibi işletim sistemleri sadece bir adet kanala sahiptir. Ama Windows 95 ve üstü, Unix, OSX gibi işletim sistemleri birden fazla kanala sahip olabilirler.

İşletim sistemi bir programı ya da bir DLL’i ilk başta işlem olarak hafızaya taşır. Bu esnada işlem eylemsiz olarak durur. Bu işleme ait kanallar ise bizim belirlediğimiz ölçüde programın kodlarını çalıştırmaya başlar.

Yine teorik olarak bilmemiz gereken diğer bir terim de quantum değeridir. Her kanalın windows tarafından atanmış bir işletilme süresi vardır. Ve terim olarak quantum olarak isimlendirilir. Bunun sadece tanımını bilmeniz yeterli.

Her kanal, çalışma esnasında kendi eax, ebx, edx gibi register verilerini tutan bir yapıya sahiptir. Bu yapıya context(içerik) adı verilmektedir. Bu yapının Delphi’deki karşılığı TContext olup, Windows unitindedir. Bu record tipini incelediğinizde bir çok register’ı barındırdığını göreceksiniz. Eğer buradaki Delphi ve Assembler ile ilgili makaleyi ve buradaki fonksiyon çağırım makenizmalarını okudu iseniz şimdi anlatacaklarımız size tanıdık gelecektir. Çünkü kanalların işleyiş mantığı fonksiyon çağırımlarına benzemektedir. Ama devam edebilmek için bunları okumak zorunda değilsiniz.

Her bir kanal sahip olduğu önceliğe göre işletim sistemi tarafından işleme alınacaktır. Bu işleme alış esnasında sahip olduğu context‘deki register değerleri yüklenir. Esp, Ebp, Eip gibi registerlar da yüklendiğinden, kanal önceden kaldığı yerden önceki stack değerlerine göre işlemine devam edecektir. Ve yine önceliğine göre belli bir süre sonunda işletim sistemi bu kanalı durdurup register değerlerini context yapısında saklar. Daha sonra diğer bir kanalın context verisini yükleyerek başka bir kanalı işlemeye geçer. Ve hakeza bu işlem tüm kanallar için devam edip gider. İşletilme ve geçiş süreleri çok kısa olduğundan, biz sanki aynı anda tüm kanallar işletiliyormuş gibi zannederiz. Halbuki bütün kanallar belli bir sıra ile çok kısa sürelerde işletilip diğer bir kanala geçilmektedir. Yani her kanal aynı anda çalışmaz, biz öyle zannederiz. Tabi bu anlattıklarımız tek işlemci ve tek çekirdek için geçerlidir. Kanalların işletilme sürelerini ise kanalların önceliği belirlemektedir. Hangi kanal daha yüksek öncelikli ise o kanal daha fazla işletilme süresine sahip olur. Eğer kanal arkaplanda çalışma üzere ayarlanmış ise, diğer kanallar işlemlerini tamamladıktan sonra ancak bu kanala sıra gelecektir. Eğer kanal çok yüksek önceliğe sahip ise uzun bir süre bu kanal işleme devam edecek ve diğer kanallara sıra gelmeyecektir.

Demek ki, aynı anda bir kaç işlem yapmak istiyorsak kafa patlatıp, parmak yormamıza gerek yokmuş. Çünkü işletim sistemi zaten sizin için bu sistemi kurmuştur. Sadece biraz vaktiniz ayırmanız ve kanallar nasıl oluşturuluyor öğrenmeniz yeterlidir.

Kanal Oluşturma Yöntemleri

Aslında böyle bir başlıkla konuya giriş yapmak istemezdim. Ama kanal oluşturmayı öğrenmeden önce bir kaç şeyi açığa kavuşturmak istiyorum. Gerek forumlardan gerekse haber guruplarından kanallarla ilgili gelen sorulardan bir çoğu kanalların yanlış oluşturulması üzerine kaynaklanan yanlışlıklardan gelmektedir.

Normalde bir kanal windows ortamında CreateThread Windows API’si ile oluşturulur. Fakat VCL bize TThread isminde bir sınıf da sunmuştur. Kullanım açısından ayırt edebileceğiniz temel nokta şudur. Eğer kanalda yapacağınız işlemler VCL sınıflarını etkilemesi gerekiyorsa TThread sınıfını kanal oluşturmak için kullanıyoruz. Yok eğer VCL sınıflarını ilgilendiren bir işlem söz konusu değilse CreateThread API’sini kullanıyoruz. Bunun neden böyle olduğunu ileride VCL ve Kanal kullanımı ile alakalı başlıkda vereceğim. Muhtemelen Bölüm 2’de göreceksiniz. Bu yüzden biraz sabır.

Başlarken bu şekilde bir giriş yapmamın sebibi buradan kaynaklanıyor. Bir çok kişi belki de Windows API’lerine karşı bir soğukluktan dolayı CreateThread ile uğraşmak istemiyor ve CreateThread ile ilgili kısımları gözü kapalı atlayabiliyor. Bu yüzden eksik kanal bilgisi ile ileride bir çok sorunla karşılaşabiliyor. Ama şimdi göreceğimiz gibi kanal oluşturma işlemi sanıldığı kadar zor ve karmaşık bir işlem değil.

Bir Kanal Oluşturalım

Kanal oluşturma ile sorumlu Windows fonksiyonu CreateThread fonksiyonudur ve aşağıdaki gibi tanımlanmıştır:



		


Bu fonksiyonun parametrelerinin kısaca açıklamasını verelim.

lpThreadAttributes: Kanalımıza atanacak olan bir çok güvenlik özelliğini belirtmemize yarar. Eğer nil girerseniz varsayılan güvenlik özellikleri kullanılacaktır. Win9x ve WinMe için bu değer nil olmalıdır. Bu konu ile alakalı daha fazla bilgi almak için sdk yardım dosyalarından SECURITY_ATTRIBUTES başlığına müracaat edebilirsiniz.

dwStackSize: Eğer kanal için özel bir stack büyüklüğü belirlemeyecekseniz bu değeri 0 olarak girmelisiniz. Böylelikle kanalın stack büyüklüğü program ile aynı olacaktır. Gerektiğinde stack boyutu otomatik olarak genişletilebilir.

lpStartAddress: Bu parametre esas işi gören parametredir. Çünkü kanal çalışmaya bu parametredeki fonksiyon işaretçisi ile beraber başlar. Burada tek yapmamız gereken fonksiyonun isminin önüne @ işareti vererek girmektir.

lpParameter: Bir önceki parametrede girdiğimiz kanal fonksiyonuna parametre yollamak istiyorsanız, bu parametrelerin içinde bulunduğu bir record’un adresini buraya girmelisiniz. Ayrıca record haricinde karakter veya sayı değelerini de parametre olarak yollayabiliriz.

dwCreationFlags: Bu parametre ile kanalın oluşturulur oluşturulmaz çalışıp çalışmayacağını belirliyoruz. Eğer bu parametreye CREATE_SUSPENDED girerseniz, kanal oluşturulur fakat kendisine çalışmaya başlaması için izin verilmez. Bu durumda siz ResumeThread fonksiyonu ile bu kanala çalışma talimatı vermedikçe kanal o şekilde çalışmadan duracaktır. Bir kez ResumeThread ile çalışmaya başladıktan sonra SuspendThread ile tekrar kanalı durdurabilirsiniz. Eğer bu parametreye 0 girerseniz, kanal oluşturulur oluşturulmaz çalışmak için sıraya girecektir.

lpThreadId: Bu parametreye kanal kimlik ID’si atanır. Buraya değeri olmayan bir Dword değişken giriyoruz. Değişken gireceğiz çünkü "var" olarak tanımlanmış. Çünkü kanal oluşturulduktan sonra Windows NT,2000 ve üstü işletim sistemlerinde kanalın ID’si bu değişkene yüklenir. Windows 9x/Me işletim sistemlerinde bu değer daima 0’dır.

Şimdi gelin bu fonksiyonu kullanarak bir kanal oluşturalım.



		

İşte hepsi bu! Tek yaptığımız sadece gerekli parametreleri kullanmak, gerisini duruma göre nil veya 0 yapmak. Bu fonskiyon çağrıldığında KanalFonksiyonu isimli fonksiyonumuz kanal içinde çalışmaya başlayacaktır.

Dilerseniz KanalFonksiyonu isimli fonksiyonumuzun tanımlamasını şimdi yapacağımız örnek içinde verelim.

Basit Bir Örnek

Şimdi oluşturduğumuz bu kanalın nasıl çalıştığını basit bir örnek ile görmeye çalışalım. Yeni bir uygulama oluşturalım ve Form üzerine bir adet button ve bir adet label koyalım. Button’nun Caption özelliğini "Oluştur ve Çalıştır" olarak değiştirelim. Ve Button’nun OnClick olayına kanalımızı oluşturan şu kodları girelim:



		

Şimdi de kanalımızda esas işi yapan KanalFonksiyonu isimli fonksiyonumuzun tanımlamasını girelim:



		

Kanal fonksiyonumuzun tanımlamasını istediğimiz gibi yapabilirdik. Burada mesela P: Pointer parametresine ihtiyaç yoktu. Ayrıca Longint çıktısını vermeye de ihtiyacımız yok. CreateThread fonksiyonunun parametre açıklamalarını hatırlarsanız, kanal fonksiyonumuza belli parametreler yollayabiliyorduk. İşte bu parametreleri pointer olarak buradan alıyoruz. Ama bu meseleye sonra geçeceğiz. Ayrıca fonksiyon tanımlamasındaki stdcall ifadesine yabancı iseniz buradaki fonksiyon çağırım makenizmaları ile ilgili makaleyi okuyabilirsiniz.

Bu fonksiyonda ekstra bir şey yapmıyoruz. Sadece bir for döngüsü var ve matematiksel bir işlem yapılıyor. For döngüsü bittiğinde ise formdaki label’a bir sonuç yazdırıyoruz.

Bu for döngüsünü, ayrı bir kanalda değil de programın ana kanalında çalıştırmaya kalksaydık muhtemelen Application.ProcessMessages ve TTimer gibi çözümlere gidecektik. Bu durum da çok fazla miktarda performans düşüklüğüne sebep olacaktı. Ayrıca işlemlerimiz genelde buradaki gibi basit matematiksel işlemler olmadığından, programda çökmelere ve donmalara sebep olacaktık.

Bu programı çalıştıralım ama button’a basmayalım. Eğer açık değilse View menüsünden "Thread Status" penceresini ve "Event Log" penceresini açalım ve görebileceğimiz bir köşeye yerleştirelim. Eğer BDS 2005 ve üstü kullanıyorsanız bu pencereler debug esnasında altta görünür biçimde hazır olacaklardır.

Ardından buttona bir kez basalım ve "Thread Status" penceresine yeni bir eleman eklendiğine dikkat edelim. Eğer buradaki eleman çok çabuk bir şekilde görünüp kayboldu ise işlemciniz benimkinden hızlı demektir :). Bu yüzden for döngüsündeki limit değeri biraz artırıp tekrar çalıştıralım.

Button’a her tıkladığınızda "Thread Status" pencersinden de takip edebileceğiniz gibi yeni bir kanal eklenecek. Tabi butona basma işini o kadar çok abartmayın. Her kanal oluşturulduğunda kendisine bir ID atanacak. Örneğimizde bu değer KimlikID değişkeninde tutuluyor. "Thread Status" pencersinde ise ThreadID sütununda bu değeri görebiliriz. Her kanal işlemini bitirdiğinde "Thread Status" pencersinden kaybolduğunu göreceksiniz. Aynı şekilde "Event Log" pencersinde de kanal’ın ID’sine göre başlama ve bitişi ile ilgili mesajları görebilirsiniz.

Kanal çalışırken program üzerinde istediğiniz işleme devam edebilirsiniz. Formu taşıyabilir, boyutlandırabilir, başka bileşen ve nesneler var ise onları kullanabilirsiniz. Ve bunu yaparken bir yandan kanal(lar) da çalışmaktadır. Aynı kanal fonksiyonunu doğrudan çağırmaya kalktığımızda formumuza döngü bitene kadar müdahale edemeyecektik.

Gördüğünüz gibi bir kaç satır kod ile kanal oluşturuveriyoruz. Tek bilmemiz gereken kısım CreateThread fonksiyonunun parametreleri. Bunların çoğunu da kullanmadık. Ama makalenin ilerleyen kısımlarında bunları da yavaş yavaş kullanıma dahil edeceğiz. İşte bir tanesi geliyor.

Kanal Fonksiyonlarına Parametre Gönderimi

CreateThread fonksiyonunun parametrelerini açıklarken lpParameter‘den söz etmiştik ve bu parametre ile kanal fonksiyonuna istediğimiz parametreyi gönderebileceğimizi belirtmiştik. Şimdi bunu nasıl yapacağımızı görelim.

Bunun için yukarıda yaptğımız örnekten faydalanacağız. İlk başta type bloğunda aşağıdaki record tanımlamasını yapalım.



		


Ardından kanal fonksiyonumuzu aşağıdaki gibi değiştirelim.



		

En son olarak button’nun OnClick olayını da aşağıdaki gibi olacak şekilde değiştirelim.



		

Aslında çok fazla bir şey yapmadık(en azından siz kopyala yapıştır yaptınız:) ). Burada basit bir işaretçi kullanımını görüyoruz. Ve parametre olarak bir record’u kullandık. Record yerine başka veri tiplerini de kullanabilirdik. Ama genelde karşılaşılan sorunlar recordları parametre olarak yollamaktan gelmektedir.

En başta verdiğimiz record tanımlamasına bakarsanız, PKanalParametresi isminde bu recordumuza işaretçi olan bir tip göreceksiniz. Parametremizi işaretçi olarak kullanacağımızdan bu tipe ihtiyacımız olacak. Ardından Button’nun OnClick olayına bakalım. Burada önceki örneğe göre fazladan 2 satır ekledik. İlk başta var bloğunda Parametreler isminde bir record işaretçisi tanımladık. Ardından işaretçi hiç bir şey ifade etmediğinden, işaretçiye ait bir recordun hafızada oluşturulması için New rutinini kullandık. Devamında bu record’un değişkenlerinden birine bir string değer atadık. CreateThread fonksiyonu parametreyi işaretçi olarak istediğinden buraya direk olarak Parametreler değişkenimizi girebiliriz. Çünkü bu değişken bir record işaretçsidir.

En son olarak yeni kanal fonksiyonumuza baktığımızda, işaretçi olarak gelen parametremizin nasıl kullanıldığını görüyoruz. Burada bizim için önemli olan kısım Dispose kısmıdır. Çünkü burada New ile oluşturduğumuz ve işaretçiye ait olan recordu hafızadan siliyoruz.

Record işaretçisi yerine normal record kullansa idik ve sonra da bunu parametre olarak geçirirken pointer olarak geçirse idik olmazmıydı. Olurdu… Üstelik New ve Dispose rutinlerini de kullanmak zorunda kalmazdık. Ama, bu durumda boş yere hafızda yer işgal edecektik. Çünkü parametre recordu sadece bir kerelik işimize yarayacak. Bu yüzden işimiz bitince Dispose ile hafızdan siliyoruz.

Bu örneğimizi de çalıştırıp deneyebilirsiniz. Ayrıca Görev Yöneticisi ile işlemciyi yüzde kaç kullandığını da görebilirsiniz. Tabi burada Sleep rutinini kullanmak yerine daha başka yapılabilecek şeyler var ama şimdilik kafa karıştırmamak için bunları sonraya bırakıyorum.

Sonuç

Bu bölümü burada noktalayalım. Gelecek bölümde kanalların nasıl birbirleri ile birlikte çalışabileceğini göreceğiz. Ayrıca Mutex’ler ve VCL ile kanal kullanımı da gelecek bölümde göreceğimiz konular arasında olacak. Böylece kanallar konusunda hiç bir şüpheniz, korkunuz kalmayacağı gibi programlarınıza da profesyonellik katacaksınız.

Gelecek bölümde buluşmak ümidi ile… Yorumlarınızı ve eleştirilerinizi bekliyorum. Yine her zaman ki gibi sorularınızı buradan yada Delphi Türkiye forumlarından iletebilirsiniz

Fatih Tolga Ata © 2007

Kaynaklar

  • Windows SDK Yardım Dosyası
  • Delphi 4 Unleashed, Charlie Calvert, Sams Pub., 1999
» Tags: ,

31 Comments

  • […] *** Fatih Tolga Ata’dan Delphi ve Kanallar ile ilgili çok güzel bir makale. Delphi ile Thread(Kanal) Kullanımı – Bölüm 1 […]

    • At 2007.10.03 10:38, Selo said:

      Dostum yiner bir yaramıza derman oldun. Ne kadar teşekkür etsek az. Senin gibi kaliteli makale yazan kişiye az rastlanıyor. Devamını dileriz.

      • At 2007.10.03 16:06, Fatih Tolga Ata said:

        Sağolasın dostum. Sizin gibi okuyan ve ilgilenen oldukça, elimizden geldiğince yazmaya devam edeceğiz inş.

        • At 2007.10.04 00:28, Hüseyin ÖZDEMİR said:

          Thread ve Veritabanı uygulamaları uzun SQL leri nasıl thread kanalında kullanabiliriz imkanı varmı ? üstad imkanı varsa hemen bir makale isterim 🙂

          eline sağlık bu arada

          • At 2007.10.04 01:48, Fatih Tolga Ata said:

            İstediğin şey olur mu bilmem ama 2. Bölümde VCL ile kullanımı anlatırken veritabanından örnek vermeyi düşünüyordum kısmetse.

            • At 2007.10.05 16:52, sadettinpolat said:

              AsyncCalls ‘i winapi ve TThread sinifi ile ugrasmak istemeyen arkadaslara tavsiye ederim. yazdiginiz her hangi bir fonksiyonu parametre olarak belirtip ilgili fonksiyonun ayri bir thread icinde calismasini sagliyor.
              http://andy.jgknet.de/async/
              bu ipucunun ardindan yaziyla ilgili olarak sunu sormak istiyorum 🙂 kanal olusturma yontemlerini ogrendik peki ya kanal durdurma yontemlerini ne zaman ogrenecez ?

              terminate ile cok guzel sonlaniyor bu kanallar ama benim ugrasipta yapamadigiim calisan bir kanalin calismasini ana kanaldan aninda durdurmak. mesela icinde kanalin durdurulmasi gerektigini kontrol eden herhangi bir kod barindirmayan bir kanal nasil durdurulur. kanal da su kodun calistigini varsayalim.

              while true do
                noop

              ben ana kanaldan bu kanali durdurmayi basaramadim.

              ikinci bir husus ise araya vcl i karistirinca kanallar bazen kilitlenmeye neden oluyor.

              mesela AsyncCalls kullanilarak hazirlanmis surdaki ornekte birinci start dugmesine basinca progressbar adim adim ilerlemeye basliyor ve o sirada biz formdaki diger elemanlari gayet rahat bir sekilde kullanmaya devam edebiliyoruz. ne zaman ki ikinci start dugmesine basiyoruz progressbarlar ilerlemesine ragmen form ve uzerindeki bilesenler donuyorlar…

              http://rapidshare.com/files/60459720/ornek1.rar.html

              makalenin ikinci baskisi gelene kadar database ve thread icin, huseyin hocam suraya goz atabilirsin.
              http://delphi.about.com/od/kbthread/a/query_threading.htm

              • At 2007.10.05 17:19, Fatih Tolga Ata said:

                AsyncCalss ile ilgili söyleyebileceğim bir şey yok. Kanal durdurma hadisesinde ve VCL kullanımını eğer ikinci bölümü beklerseniz cevaplarınızı bulacaksınız.
                Teşekkürler.
                vesselam.

                • At 2007.10.06 22:32, Türkcan Fidan said:

                  Ellerine sağlık hocam, başarılarının devamını dileriz.

                  • At 2007.11.07 14:00, Mehmet A.Cicek said:

                    Size ne kadar tesekkur etsek azdir.Cok guzel ve aydinlatici bir makale.Benzer makalelerinizin devamini dileriz.iyi calismalar

                    • At 2007.12.30 17:27, bekir murat ersoy said:

                      arkadaş anlamadığım bir konu ama ileri seviye delpiyide öğrenmek istiyorum bunun adına da çok güzel bi amakale olmuş devamlarını dilerim

                      • At 2008.01.17 16:10, bünyamin atak said:

                        Gördüğüm en yararlı çalışmalardan biri. Teşekkür ediyorum.

                        • At 2008.08.01 16:48, abidin yavuz said:

                          Çalışmanız cok iyi aslında cok iyi anlatmışsınız ama ben yapamadım bu thread olayını bir formun mimized ve maximized olayına nasıl adapte ederiz
                          ben formumun ekrana arasıra gelmesini istiyorm timer nesnesine bağladım istediğimi alamadım butonlar pasif oluyo(tıklayamıyorum) thread a adapte edebilirsem cözmüş olacam teşekkürler.

                          • […] Bölüm 1 […]

                            • At 2009.04.02 21:28, orçun said:

                              Merhaba üstad,

                              Öncelikle böyle güzel bir yazı dizisi için çok teşekkürler. Yalnız bir sorum olacaktı. CreateThread ile çalıştırılan bir kanalın içerisinden yine CreateThread metoduyla başka bir kanal açabiliyor muyuz?

                              Saygılar

                              • At 2009.04.03 11:12, Fatih Tolga Ata said:

                                Bir kanalın içinde başka bir kanal diyorsan böyle bir şey olmaz. Eğer bir kanalın içinden CreateThread ile bir kanal oluşturursan bu kanal farklı bir kanal olacaktır, diğer kanalın içinde olmayacaktır. Sonuçta oluşturduğun tüm kanallar, zaten bir başka kanalın içinden CreateThread çağrılarak oluşturulur. Mesela genelde, kanalları oluşturduğumuz programın ana kanalı da sonuçta bir kanaldır, her ne kadar ana kanal otomatik olarak oluşssa da…

                                • At 2010.01.14 23:36, Knn said:

                                  Fatih Bey Merhaba,

                                  Konu anlatımınız ve paylaşımınız için çok teşekkürler, emeğinize sağlık. Benim size sormak istediğim bir kaç konu var thread ile ilgili. Mailinizi öğrenemedim.

                                  • At 2010.04.05 21:07, Bulent UNALMIS said:

                                    Threat icinden forma ait textbox yada label gibi nesenelerin text iceriklerini degistirebilirmiyim?

                                    • At 2010.07.17 11:47, yusuf şimşek said:

                                      emeğinize sağlık.
                                      çok güzel bir makale olmuş

                                      • At 2010.09.24 14:58, Mikail Abdullah said:

                                        Fatih bey merhaba,
                                        Emeğiniz için teşekür edererim. Ama ben yukarıdaki Basit Bir Örnek kısmında yazmış olduğunuz kodu aynen copy/paste yaptım ama Variable required hatası veriyor.

                                        CreateThread(nil, 0, @KanalFonksiyonu, nil, 0, KimlikID);

                                        Hata şu kodu işaret ediyor. Acaba nerede yanlış yaptım?

                                        • At 2011.02.27 06:06, tavşanlılı said:

                                          public yada private kısımdaki
                                          function KanalFonksiyonu(P: Pointer): Longint; stdcall;

                                          satırını sildiğinizde sorun kalmaz.
                                          ayrıca function KanalFonksiyonu(P: Pointer): Longint; stdcall; nin başında TForm1. gibi bir nesne tanımı olmamalı.

                                        • At 2011.02.27 06:01, tavşanlılı said:

                                          Merhaba,

                                          Sanırım örnekte anlatan arkadaşın da gözden kaçırdığı bişey var.
                                          Functionları ayrı kanalda açılamıyor gördüğüm kadarıyla.
                                          Ki sonuçta tüm programların ana procedureleri(MainThread) var.
                                          Yani buradaki function ı procedure yaptığınızda sorun kalmaz.
                                          Sonuçta o yeni bir thread da açılan procedure ye P: Pointer değeri ile kendi adresi geçilir.
                                          Ve bunu kullanarak parametre gönderebilirsiniz.
                                          Bu şekilde procedure içinde ister veritabanına bağlanın isterseniz soketten kullanıcıları kontrol edin hiç farketmez.
                                          Her türlü kullanabilirsiniz.

                                          Tek merak ettiğim tanımlanan function nasıl olur da thread ile açıldıktan sonra açıldığı thread içine geri bir değer döndürebilir.Gerçekten bunu yapan varsa daha öğrenilecek çok şey var demektir.

                                          • At 2011.06.07 19:26, Ahmet Genc said:

                                            Label ile aynı pencereye editbox koyuyorum.

                                            Edit1.Text := IntToStr(Toplam);

                                            Fakat Edit1 Undeclared identified hatası alıyorum. Edit1 otomatik olarak tanımlanıyor. Başka ne yapmam gerekiyor?

                                            Saygılar.

                                            • At 2012.02.24 15:20, Alper said:

                                              güzel bir makele olmuş elinize sağlık, takıldığım bir nokta var
                                              “Record işaretçisi yerine normal record kullansa idik ve sonra da bunu parametre olarak geçirirken pointer olarak geçirse idik olmazmıydı. Olurdu… Üstelik New ve Dispose rutinlerini de kullanmak zorunda kalmazdık” Burada şöyle bir sıkıntı oluşmuyor mu? :
                                              button1.click’ten çıkıldığında normal record kapsam dışına çıktığından free edildiğinden, KanalFonksiyonu geçersiz bir lokasyona bakmış olmaz mı?
                                              yada ben neyi kaçırıyorum .

                                              • At 2012.02.25 12:59, Fatih Tolga Ata said:

                                                Orada da bahsettiğim gibi, record hafızada kalacaktır. Eğer bunu dert etmiyorsanız pointer kullanmak zorunda değilsiniz. Çünkü record’lar free edilmek zorunda değiller. Record’un kapsamı fonksiyondan geneldir. Yani bu recordu thread dışında oluşturup, thread fonksiyonuna parametre olarak yolluyorsunuz. Bu durumda kanal fonnksiyonu geçersiz olduğunda bile bu değişken kalacaktır.
                                                Bu yapı genel kullanım için örnek verildi. Eğer burada işaretçi yerine normal record’lu bir örnek verse idim ve millet de bu şekilde öğrense idi, bu durum bazı senaryolarda sıkıntı çıkaracaktı. Mesela bu record parametresini programın genel kapsamında var olduğunu düşünün. Ve bu record’un megabaytlarca veri tuttuğunu düşünün. Bu durumda record kaybolmayacağı için program işini bitirse de gereksiz yere hafızada tuttuğu yer şişkin olacaktır. Bu yüzden her yerde işe yarayan pointer mantığını verdik.

                                              • At 2012.04.06 19:28, hasan said:

                                                öncelikle makale için teşekkürler hocam, benim de bir sorum olacaktı. makalelerini çok yararlı buldum ve amatör olarak da delphi projeleri üretsem çok işime yaradı. fakat bu kanallar konusunda bir yerde tıkandım. projemde bir webbrowser var ve otomatik formu doldurtmaya çalışıyorum diyelim. kanal oluşturduktan sonra kanalın çağırdığı fonksiyon webbrowser da linki navigate ediyor fakat sayfa yüklendikten sonra yine aynı fonksiyonu kullanarak yüklenen sayfadaki form nesnelerine ulaşmama izin vermiyor ve debugger de aldığım hata “access violation at ….” cpu penceresinde baktığımda add esp,$04 satırını gösteriyor. stuck üzerine veri yazarken mi hata oluşuyor anlayamadım. fonksiyon çağırma mekanizmasını stdcall olarak değil de safecall olarak kullanınca hata vermiyor ama nesneler üzerinde yine işlem yapmıyor. Yardımcı olursanız çok sevinirm hocam, şimdiden teşekkür ederim.

                                                • At 2012.05.30 15:59, Delphici said:

                                                  Thread uygulamalarını Delphi nin hangi versiyonunundan itibaren kullamabiliyoruz?

                                                  • At 2013.05.31 12:06, Adem Kocamaz said:

                                                    Merhabalar size ne kadar teşekkür etsem az olur. Sayenizde Thread ile ufkum değişti.

                                                    • At 2013.05.31 12:09, Adem Kocamaz said:

                                                      ilk denediğimde fonksiyonu Private kısmında ve button1 click hemen altında denedim Variable Required hatası verdi. Bende fonksiyonu button1click olayında tanımladım.
                                                      procedure TForm1.Button1Click(Sender: TObject);
                                                      function KanalFonksiyonu(P: Pointer): Longint; stdcall;
                                                      var
                                                      i: Integer;
                                                      Toplam: Int64;
                                                      begin
                                                      Toplam := 0;
                                                      for i := 0 to 1000000000 do
                                                      begin
                                                      Toplam := Toplam + i;
                                                      Toplam := Toplam shl 4;
                                                      end;
                                                      Form1.Label1.Caption := ‘Kanal işlemini tamamladı. Sonuç:’ + IntToStr(Toplam);
                                                      Result:=Toplam;
                                                      end;
                                                      var
                                                      KanalID:DWORD;
                                                      begin
                                                      CreateThread(nil, 0, @KanalFonksiyonu, nil, 0, KanalID);
                                                      end;

                                                      bu şekilde. Hata giderildi. Bir de uyarı verdi fonksiyon dönüş değeri yok. Result:=Toplam; dedim.

                                                      • At 2013.05.31 12:09, Adem Kocamaz said:

                                                        Kullandığım IDE Delphi 2009 Win32

                                                        • At 2013.08.12 15:40, Hakan GÜVEN said:

                                                          İyi günler hocam. şu record tanımlamasını ben yapamadım. kopyala yapıştır yapınca hata verdi. acaba başka bi değişiklik mi yapıyoruz?

                                                          • At 2016.04.24 10:47, Marubionida said:

                                                            2. Последите за поведением мужчины, когда вы с ним стоите в окружении других людей. Если мужчина стоит несколько позади вас или впереди, это может быть знаком того, что он не очень уверен в своих чувствах или просто не относится к вам серьезно. Влюбленный должен стоять рядом, плечом к плечу.

                                                            (Required)
                                                            (Required, will not be published)