Konuyu Oyla:
  • Derecelendirme: 5/5 - 1 oy
  • 1
  • 2
  • 3
  • 4
  • 5
100 puan değerinde (Threading)
#31
Merhaba,

Aşağıdaki gibi bir kod istediğimiz sonuca ulaştırıyor:

procedure TForm1.Button1Click(Sender: TObject);
var
 H: THandle;
begin
 Event.ResetEvent;
 H := Event.Handle;

 TThread.CreateAnonymousThread(
  procedure
  begin
    Sleep(10000);
    Event.SetEvent;
  end
 ).Start;

 while True do
 begin
   case MsgWaitForMultipleObjects(1, H, FALSE, INFINITE, QS_ALLINPUT) of
     WAIT_OBJECT_0: Break;
     else Application.ProcessMessages;
   end;
 end;

 // Burada Event için bekleme kodunuz olacak. Ve bu kod uygulamanızı kilitlemeyecek. Progressbar'ın hareket ettiğini
 // Timer'ın ilgili zaman değerlerini label'a yazdığını gözlemlemeniz gerek.

 Memo1.Lines.Add('Bu satır ancak 10 saniye sonra işletilecek. Ancak bu arada formunuz interaktif olacak. Memoya tıklayıp yazı yazabileceksiniz. Ancak CPU kullanım oranınız da yüksek olmayacak. !');
end;

MsgWaitForMultipleObjects fonksiyonunun ne yaptığını okuduğunuz zaman bu kod basit:
- Bu fonksiyon aslında birden fazla sync edilebilen nesneyi bekliyor. Bizim örneğimizde bir tane olduğu için ilk parametremiz 1
- 2. parametre aslında HANDLE dizisi. Birden fazla nesne olduğunda işleri karıştıracak, ama tek nesne için iş kolay. Örnekteki gibi Event'in handle değerini bir değişkene alıp gönderebiliriz.
- 3. parametre bütün nesneleri bekleyip beklemeyeceğini belirliyor. Bizim örneğimiz için TRUE veya FALSE olması anlamsız.
- 4. parametre timeout. Biz thread'in bitişini bilmediğimiz için INFINITE (sonsuz) dedik. 
- Son parametre ise bu fonknsiyonun hangi Input'larda geri döneceği. Biz bütün inputlar dedik, böylece klavye, mouse, SendMessage gibi bütün input işlemleri için fonksiyon kesilecek.

Bütün inputlarda fonksiyon kesileceği için bunu while döngüsü içine aldım. Dikkat edecek olursanız Thread bitmediği sürece bu döngüden çıkamıyor.

Tuğrul Bey, umarım aradığınız çözüm budur.

Kod çalışıyor, ama bu kod programın içine gömebileceğiniz bir kod değil! Öncelikle sonsuza kadar bekleme olmaz Smile Ayrıca bu şekilde bekleme yapmak zorunda kalıyorsanız programın tasarımını bir kere daha düşünün, büyük ihtimalle bir yerde yanlış yapıyorsunuz. Son olarak, Application.ProcessMessages çok gıcık, tehlikeli, her kullandığımda kendimi kötü hissettiğim, kötü evlat gibi (artık ekleyebildiğiniz ne varsa ekleyin) bir prosedür. Programın içinde buna ihtiyaç duyuyorsanız gene program tasarımında sorun var demektir. Bütün bunları yazıyorum, ama kendi programlarımda da bu sorunları yaşıyorum. Maalesef program yazmak çok hızlı bir iş gibi düşünülüyor, oysa değil. Hızlı yazdığınız zaman da Application.ProcessMessages veya yukarıdaki gibi bekleme kodları yazmak gerekebiliyor (Ben Muharrem Bey'in yazdığına benzer kodlar yazıyordum, ama bu yenisi diğerinden daha iyi Smile ). 

İyi çalışmalar
Cevapla
#32
Ayrıca WaitForMultipleObjects metodu için şu linkte bilgi var, sanırım yazarı tanıyoruz bir yerlerden  Cool

@Bahadir.Alkac sanırım doğru yolu buldunuz, tebrikler desem mi acaba şimdiden  Rolleyes
Cevapla
#33
Merhaba,
Öncelikle bu değerli fikir ve araştırma jimnastiği için @Tuğrul HELVACI hocama teşekkürlerimi sunuyorum.
Amacımın puan olmadığını belirterek, söze başlayayım.
Beklenen yapının yakınından geçer mi bilmiyorum ama platform bağımsız örnek arayanlar için bir katkıda bulunmak istiyorum.





Kullanılan nesneler:

styled.png

Kodlama:
uses
 FMX.DialogService, System.Threading;


procedure TForm1.Button1Click(Sender: TObject);
begin
 TDialogService.InputQuery('Bekleme Süresi (sn.): ', ['Süre'], ['0'],
   procedure(const AResult: TModalResult; const AValues: array of string)
   var
     BeklemeSuresi: Integer;
   begin
     case AResult of
       mrOK:
         begin
           BeklemeSuresi := AValues[0].Trim.ToInteger;
           if (BeklemeSuresi > 0) then
           begin
             TThread.CreateAnonymousThread(
               procedure
               var
                 Bekle: ITask;
               begin
                 Bekle := TTask.Create(
                   procedure
                   begin
                     sleep(BeklemeSuresi * 1000);
                   end);
                 Bekle.Start;

                 TTask.WaitForAll(Bekle);
                 TThread.Synchronize(Nil,
                   procedure
                   begin
                      Memo1.Lines.Add
                        (Format('%s Saniyelik bekleme süresi bitti',
                        [BeklemeSuresi.ToString]));
                   end);
               end).Start;
           end
           else
             Memo1.Lines.Add('Bekleme süresi sıfırdan farklı olmalıdır!')
         end;
     end;
   end);
end;
While true do; Hayat döngüsü, kısır değildir! Yapılan bir yanlış, o döngünün dışına çıkmanızı sağlayacaktır.
WWW
Cevapla
#34
@Tuğrul HELVACI aşağıdaki cevabınıza istinaden yazıyorum.
Alıntı:Merhaba üstadım, aslında ben kullanılabilecek API'leri vermiştim. Yapılacak tek şey, o API'lerin ne yaptığını okumak, anlamak, anlanılanları koda döküp denemek ve buraya gelip paylaşmaktı.

Bu nedenle, kendi çözümümü paylaşmayacağım. Çünkü samimi bir çaba hissetmiyorum açıkçası.


Beni bu işin okulunda okuma imkanı olmadan, kendini kurs ve türkçe kitaplardan ve internet üzerinden okuduğu türkçe dökümanlar ile geliştirmeye çalışan biri olarak görün lütfen.
Şimdi çok iyi almanca, fransızca bildiğimi fakat ingilizcemin olmadığını farz edelim.
sizin linklerini verdiğiniz ingilizce kaynaklara bakarak ne kadar bu konuyu anlayıpta size samimi bir şekilde dönüş yapmaya çalışabilirim.

Demem odur ki bir tartışma konusu açıldığında ve belli fikirler ortaya çıkıp harmanlandıktan sonra 
"Bu nedenle, kendi çözümümü paylaşmayacağım." 
ifadesi yerine bu işin bir üstadı olarak kendi fikrinizi ve doğru yolun "....." şekilde ve nedenlerininde "....." şeklinde olduğunu açıklayan bir yazı ele almanız daha uygun olmazmı.
Bu platformun amaçlarından biri olan bilgiyi paylaşmak ve bilmeyenlere yol açmak daha doğru olmazmı.

Saygılarımla
Bu dünyada kendine sakladığın bilgi ahirette işine yaramaz. 
Cevapla
#35
(02-05-2018, Saat: 09:23)Bahadir.Alkac Adlı Kullanıcıdan Alıntı: Merhaba,

Aşağıdaki gibi bir kod istediğimiz sonuca ulaştırıyor:

procedure TForm1.Button1Click(Sender: TObject);
var
 H: THandle;
begin
 Event.ResetEvent;
 H := Event.Handle;

 TThread.CreateAnonymousThread(
  procedure
  begin
    Sleep(10000);
    Event.SetEvent;
  end
 ).Start;

 while True do
 begin
   case MsgWaitForMultipleObjects(1, H, FALSE, INFINITE, QS_ALLINPUT) of
     WAIT_OBJECT_0: Break;
     else Application.ProcessMessages;
   end;
 end;

 // Burada Event için bekleme kodunuz olacak. Ve bu kod uygulamanızı kilitlemeyecek. Progressbar'ın hareket ettiğini
 // Timer'ın ilgili zaman değerlerini label'a yazdığını gözlemlemeniz gerek.

 Memo1.Lines.Add('Bu satır ancak 10 saniye sonra işletilecek. Ancak bu arada formunuz interaktif olacak. Memoya tıklayıp yazı yazabileceksiniz. Ancak CPU kullanım oranınız da yüksek olmayacak. !');
end;

MsgWaitForMultipleObjects fonksiyonunun ne yaptığını okuduğunuz zaman bu kod basit:
- Bu fonksiyon aslında birden fazla sync edilebilen nesneyi bekliyor. Bizim örneğimizde bir tane olduğu için ilk parametremiz 1
- 2. parametre aslında HANDLE dizisi. Birden fazla nesne olduğunda işleri karıştıracak, ama tek nesne için iş kolay. Örnekteki gibi Event'in handle değerini bir değişkene alıp gönderebiliriz.
- 3. parametre bütün nesneleri bekleyip beklemeyeceğini belirliyor. Bizim örneğimiz için TRUE veya FALSE olması anlamsız.
- 4. parametre timeout. Biz thread'in bitişini bilmediğimiz için INFINITE (sonsuz) dedik. 
- Son parametre ise bu fonknsiyonun hangi Input'larda geri döneceği. Biz bütün inputlar dedik, böylece klavye, mouse, SendMessage gibi bütün input işlemleri için fonksiyon kesilecek.

Bütün inputlarda fonksiyon kesileceği için bunu while döngüsü içine aldım. Dikkat edecek olursanız Thread bitmediği sürece bu döngüden çıkamıyor.

Tuğrul Bey, umarım aradığınız çözüm budur.

Kod çalışıyor, ama bu kod programın içine gömebileceğiniz bir kod değil! Öncelikle sonsuza kadar bekleme olmaz Smile Ayrıca bu şekilde bekleme yapmak zorunda kalıyorsanız programın tasarımını bir kere daha düşünün, büyük ihtimalle bir yerde yanlış yapıyorsunuz. Son olarak, Application.ProcessMessages çok gıcık, tehlikeli, her kullandığımda kendimi kötü hissettiğim, kötü evlat gibi (artık ekleyebildiğiniz ne varsa ekleyin) bir prosedür. Programın içinde buna ihtiyaç duyuyorsanız gene program tasarımında sorun var demektir. Bütün bunları yazıyorum, ama kendi programlarımda da bu sorunları yaşıyorum. Maalesef program yazmak çok hızlı bir iş gibi düşünülüyor, oysa değil. Hızlı yazdığınız zaman da Application.ProcessMessages veya yukarıdaki gibi bekleme kodları yazmak gerekebiliyor (Ben Muharrem Bey'in yazdığına benzer kodlar yazıyordum, ama bu yenisi diğerinden daha iyi Smile ). 

İyi çalışmalar

İyi akşamlar. Öncelikle kıymetli bilgilerinizi paylaştığınız için teşekkür ederim. Belirtmek isterim ki, ben bir çözüm aramıyorum. Amacım, önemli gördüğüm bu husus hakkında bir bilinç oluşmasını sağlamaya çalışmaktı.

Müsaadeniz ile yazdıklarınızın bir kısmına iştirak etmediğimi belirtmek isterim. "Sonsuza dek bekleme olmaz !" demişsiniz. INFINITE sonsuzluk anlamına gelse de sizin de bileceğiniz gibi esasen 49.7 güne tekabül eder. Bazen bir thread, başka thread'lerin işlerini tamamlamalarını beklemek durumunda kalır.Sırası ile yapılması gereken işler olabilir. Ya da bu tarz senaryolar çoğaltılabilir. Bu durumda, yapılacak işlerin ne kadar süreceği bilinmiyor ise INFINITE ile beklemekten başka bir çare yoktur.

 Elbette işlerin bitmesini beklemenin başka yolları da vardır. Örneğin pencereler arası mesajlaşma API'leri (PostMessage, SendMessage vb.) ya da callback mekanizmaları gibi. Ancak, bahse konu kernel senkronizasyon nesnelerinin beklenmesi son derece yaygın bir uygulama alanına sahiptir ve bunun sisteme de faydası olduğu yadsınamaz bir gerçektir. (Bir thread nonsignaled (işaretli olmayan) kernel nesnelerinden birisini beklemeye başladığında aslında işletim sistemi ilgili thread'i pause eder ve başka thread'leri işletmeye devam eder.)

Bu bağlamda, bu tarz bir beklemenin "tasarım hatası" ile ilişkilendirilmesini pek kabul edemiyorum.

Application.ProcessMessages çağrımına neden gıcık olduğunuzu, ona neden bu denli temkinli yaklaştığınızı bilmiyorum ama; Application.ProcessMessages altında yatan API'ler (GetMessage, TranslateMessage, DispatchMessage) olmadan Windows ortamında bir uygulamadan bahsedilemeyeceğini siz de benim kadar bilirsiniz.

Aslında kafayı fazla karıştırmaya gerek yok. Genel geçer çok önemli bir kural var Windows işletim sisteminde programlamada. "Pencere create etmiş her bir thread, ilgili pencerenin mesaj kuyruğunu tüketmelidir".

Bunun istisnası yoktur. Aksi durumda, beklenmedik durumlar (genellikle kilitlenmeler) oluşur. Bu neden ile; ana thread haricinde oluşturduğumuz thread'lerimiz içinde, bir pencere oluşturuyor isek (Form'da bir penceredir) bu pencerenin mesaj döngüsünü kesinlikle tüketmeliyiz.

 Bu arada thread'ler içinde gizli biçimlerde pencere create eden API'ler vardır. Bunlara da dikkat etmek gerekir. (Bunların en önemlisi, CoInitialize API'sidir. Sık kullanılır). İçinde pencere oluşturan thread'lerin beklenmesi için en uygun API MsgWaitForMultipleObject/Ex API'sidir.

  Thread'ler, uygulama penceresinin mesajlarını tüketen API'leri çağırmak(Application.ProcessMessages, PeekMessage vb) aslında; paralel programlamanın gücünden istifade etmeye çalışmaktır. Yıl 2018 ve biz hâla tek çekirdekli programlar geliştiriyor isek, hatayı biraz da kendimizde aramamız gerekir. Bu nedenler ile yoğun bir şekilde, tüm arkadaşlarımı korkulan multi-thread konseptine yaklaştırmaya gayret ediyorum tüm gücümle. Ancak sebebine anlam veremediğim çok kuvvetli bir direnç ile karşılaşıyorum her daim. Kimbilir belki ben iyi anlatamıyorum, önemine vurgu yapamıyorum. Bilemiyorum.

Birden fazla thread ile çalışmaya başladığınızda uygulamalarınız bir t zamanında çok daha fazla iş yapacak demektir. Programınız bir iş yaparken aynı anda bir başka iş daha yapabilecektir. (Aslında öyle değil tabii. Windows gerçek bir multithreaded işletim sistemi değildir. Sadece simüle eder.) Bunun faydası kime olacak peki ? Elbette programınızı kullanacak kullanıcılara. Amiyane tabir ile yağ gibi akan bir programınız olacak.

 Bu konu başlığı altındaki WaitMessage API'si de çağrıldığı thread'in mesaj kuyruğuna bir mesaj ulaşana kadar bekleme işini yapar. İlgili MSDN dökümanlarını inceleyenler göreceklerdir. MsgWaitForMultipleObjects API'si gerçekten de güçlü bir API'dir ve yapabildiklerini görünce; insanın içinde "onu kullanmalıyım" düşünceni oluşturur.

Herneyse, uzunca yazarak gözlerinizi ağrıttı isem affola.
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#36
(02-05-2018, Saat: 12:34)Fesih ARSLAN Adlı Kullanıcıdan Alıntı: Merhaba,
Öncelikle bu değerli fikir ve araştırma jimnastiği için @Tuğrul HELVACI hocama teşekkürlerimi sunuyorum.
Amacımın puan olmadığını belirterek, söze başlayayım.
Beklenen yapının yakınından geçer mi bilmiyorum ama platform bağımsız örnek arayanlar için bir katkıda bulunmak istiyorum.





Kullanılan nesneler:

styled.png

Kodlama:
uses
 FMX.DialogService, System.Threading;


procedure TForm1.Button1Click(Sender: TObject);
begin
 TDialogService.InputQuery('Bekleme Süresi (sn.): ', ['Süre'], ['0'],
   procedure(const AResult: TModalResult; const AValues: array of string)
   var
     BeklemeSuresi: Integer;
   begin
     case AResult of
       mrOK:
         begin
           BeklemeSuresi := AValues[0].Trim.ToInteger;
           if (BeklemeSuresi > 0) then
           begin
             TThread.CreateAnonymousThread(
               procedure
               var
                 Bekle: ITask;
               begin
                 Bekle := TTask.Create(
                   procedure
                   begin
                     sleep(BeklemeSuresi * 1000);
                   end);
                 Bekle.Start;

                 TTask.WaitForAll(Bekle);
                 TThread.Synchronize(Nil,
                   procedure
                   begin
                      Memo1.Lines.Add
                        (Format('%s Saniyelik bekleme süresi bitti',
                        [BeklemeSuresi.ToString]));
                   end);
               end).Start;
           end
           else
             Memo1.Lines.Add('Bekleme süresi sıfırdan farklı olmalıdır!')
         end;
     end;
   end);
end;

Üstad, ellerinize sağlık. Lâkin; sizin örneğinizde bir thread içinde create edilen bir task (bir başka deyişle thread) bekleniliyor. Asıl problemli olan; uygulamanın ana thread'inin bir başka thread'i beklediği durumdur. Normal koşullar altında (Sleep, WaitForSingleObject, WaitForMultipleObjects vb) yapacağınız tüm beklemeler ana thread'i bloke edecektir.

Benim dikkat çekmeye çalıştığım nokta da burası ;-)
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#37
(02-05-2018, Saat: 13:01)adelphiforumz Adlı Kullanıcıdan Alıntı: @Tuğrul HELVACI aşağıdaki cevabınıza istinaden yazıyorum.
Alıntı:Merhaba üstadım, aslında ben kullanılabilecek API'leri vermiştim. Yapılacak tek şey, o API'lerin ne yaptığını okumak, anlamak, anlanılanları koda döküp denemek ve buraya gelip paylaşmaktı.

Bu nedenle, kendi çözümümü paylaşmayacağım. Çünkü samimi bir çaba hissetmiyorum açıkçası.


Beni bu işin okulunda okuma imkanı olmadan, kendini kurs ve türkçe kitaplardan ve internet üzerinden okuduğu türkçe dökümanlar ile geliştirmeye çalışan biri olarak görün lütfen.
Şimdi çok iyi almanca, fransızca bildiğimi fakat ingilizcemin olmadığını farz edelim.
sizin linklerini verdiğiniz ingilizce kaynaklara bakarak ne kadar bu konuyu anlayıpta size samimi bir şekilde dönüş yapmaya çalışabilirim.

Demem odur ki bir tartışma konusu açıldığında ve belli fikirler ortaya çıkıp harmanlandıktan sonra 
"Bu nedenle, kendi çözümümü paylaşmayacağım." 
ifadesi yerine bu işin bir üstadı olarak kendi fikrinizi ve doğru yolun "....." şekilde ve nedenlerininde "....." şeklinde olduğunu açıklayan bir yazı ele almanız daha uygun olmazmı.
Bu platformun amaçlarından biri olan bilgiyi paylaşmak ve bilmeyenlere yol açmak daha doğru olmazmı.

Saygılarımla

Sevgili kardeşim, belli ki beni pek tanımıyorsunuz. Aksi durumda, insanların bir şeyleri öğrenebilmeleri adına amiyane tabir ile çırpındığımı da bilirdiniz. Ancak, hazırcılığı hiç sevmem. Konuyu baştan aşağı bir kere daha okur iseniz eğer; siz de farkedeceksiniz ki, bir iki arkadaş haricinde samimi olarak fikir beyan eden, merak edip vakit ayırabilen, öğrenmenin hazzını yaşayan insan sayısı pek de fazla değil. Oysa konu içinde ilgili API'ler de verilmiş idi.

 Ben ingilizce bilmiyorum demek, hele bu dönemde hiç de geçer akçe değil kusura bakmayın lütfen. İnanılmaz imkanlar var. Google Translate gibi Türkçe çeviriye düşman bir çeviri aracına bile verseniz ilgili makaleleri yine de anlamak isteyenler için bir kaynak teşkil eder. Velhasıl, 20+ senelik yazılım tecrübelerime dayanarak artık kimin neyi neden yaptığını ve neden yapmadığını çok iyi anlayabiliyorum. Bu bağlamda, bilgi saklamadığımı herkes bilir. Ancak, yine pek çok arkadaşımız bilir ki; ben insanlara balık tutmayı öğretmeye çalışırım, balık vermem.

Saygılar, sevgiler bizden.
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#38
(02-05-2018, Saat: 22:20)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı:
(02-05-2018, Saat: 09:23)Bahadir.Alkac Adlı Kullanıcıdan Alıntı: Merhaba,

Aşağıdaki gibi bir kod istediğimiz sonuca ulaştırıyor:

procedure TForm1.Button1Click(Sender: TObject);
var
 H: THandle;
begin
 Event.ResetEvent;
 H := Event.Handle;

 TThread.CreateAnonymousThread(
  procedure
  begin
    Sleep(10000);
    Event.SetEvent;
  end
 ).Start;

 while True do
 begin
   case MsgWaitForMultipleObjects(1, H, FALSE, INFINITE, QS_ALLINPUT) of
     WAIT_OBJECT_0: Break;
     else Application.ProcessMessages;
   end;
 end;

 // Burada Event için bekleme kodunuz olacak. Ve bu kod uygulamanızı kilitlemeyecek. Progressbar'ın hareket ettiğini
 // Timer'ın ilgili zaman değerlerini label'a yazdığını gözlemlemeniz gerek.

 Memo1.Lines.Add('Bu satır ancak 10 saniye sonra işletilecek. Ancak bu arada formunuz interaktif olacak. Memoya tıklayıp yazı yazabileceksiniz. Ancak CPU kullanım oranınız da yüksek olmayacak. !');
end;

MsgWaitForMultipleObjects fonksiyonunun ne yaptığını okuduğunuz zaman bu kod basit:
- Bu fonksiyon aslında birden fazla sync edilebilen nesneyi bekliyor. Bizim örneğimizde bir tane olduğu için ilk parametremiz 1
- 2. parametre aslında HANDLE dizisi. Birden fazla nesne olduğunda işleri karıştıracak, ama tek nesne için iş kolay. Örnekteki gibi Event'in handle değerini bir değişkene alıp gönderebiliriz.
- 3. parametre bütün nesneleri bekleyip beklemeyeceğini belirliyor. Bizim örneğimiz için TRUE veya FALSE olması anlamsız.
- 4. parametre timeout. Biz thread'in bitişini bilmediğimiz için INFINITE (sonsuz) dedik. 
- Son parametre ise bu fonknsiyonun hangi Input'larda geri döneceği. Biz bütün inputlar dedik, böylece klavye, mouse, SendMessage gibi bütün input işlemleri için fonksiyon kesilecek.

Bütün inputlarda fonksiyon kesileceği için bunu while döngüsü içine aldım. Dikkat edecek olursanız Thread bitmediği sürece bu döngüden çıkamıyor.

Tuğrul Bey, umarım aradığınız çözüm budur.

Kod çalışıyor, ama bu kod programın içine gömebileceğiniz bir kod değil! Öncelikle sonsuza kadar bekleme olmaz Smile Ayrıca bu şekilde bekleme yapmak zorunda kalıyorsanız programın tasarımını bir kere daha düşünün, büyük ihtimalle bir yerde yanlış yapıyorsunuz. Son olarak, Application.ProcessMessages çok gıcık, tehlikeli, her kullandığımda kendimi kötü hissettiğim, kötü evlat gibi (artık ekleyebildiğiniz ne varsa ekleyin) bir prosedür. Programın içinde buna ihtiyaç duyuyorsanız gene program tasarımında sorun var demektir. Bütün bunları yazıyorum, ama kendi programlarımda da bu sorunları yaşıyorum. Maalesef program yazmak çok hızlı bir iş gibi düşünülüyor, oysa değil. Hızlı yazdığınız zaman da Application.ProcessMessages veya yukarıdaki gibi bekleme kodları yazmak gerekebiliyor (Ben Muharrem Bey'in yazdığına benzer kodlar yazıyordum, ama bu yenisi diğerinden daha iyi Smile ). 

İyi çalışmalar

İyi akşamlar. Öncelikle kıymetli bilgilerinizi paylaştığınız için teşekkür ederim. Belirtmek isterim ki, ben bir çözüm aramıyorum. Amacım, önemli gördüğüm bu husus hakkında bir bilinç oluşmasını sağlamaya çalışmaktı.

Müsaadeniz ile yazdıklarınızın bir kısmına iştirak etmediğimi belirtmek isterim. "Sonsuza dek bekleme olmaz !" demişsiniz. INFINITE sonsuzluk anlamına gelse de sizin de bileceğiniz gibi esasen 49.7 güne tekabül eder. Bazen bir thread, başka thread'lerin işlerini tamamlamalarını beklemek durumunda kalır.Sırası ile yapılması gereken işler olabilir. Ya da bu tarz senaryolar çoğaltılabilir. Bu durumda, yapılacak işlerin ne kadar süreceği bilinmiyor ise INFINITE ile beklemekten başka bir çare yoktur.

 Elbette işlerin bitmesini beklemenin başka yolları da vardır. Örneğin pencereler arası mesajlaşma API'leri (PostMessage, SendMessage vb.) ya da callback mekanizmaları gibi. Ancak, bahse konu kernel senkronizasyon nesnelerinin beklenmesi son derece yaygın bir uygulama alanına sahiptir ve bunun sisteme de faydası olduğu yadsınamaz bir gerçektir. (Bir thread nonsignaled (işaretli olmayan) kernel nesnelerinden birisini beklemeye başladığında aslında işletim sistemi ilgili thread'i pause eder ve başka thread'leri işletmeye devam eder.)

Bu bağlamda, bu tarz bir beklemenin "tasarım hatası" ile ilişkilendirilmesini pek kabul edemiyorum.

Application.ProcessMessages çağrımına neden gıcık olduğunuzu, ona neden bu denli temkinli yaklaştığınızı bilmiyorum ama; Application.ProcessMessages altında yatan API'ler (GetMessage, TranslateMessage, DispatchMessage) olmadan Windows ortamında bir uygulamadan bahsedilemeyeceğini siz de benim kadar bilirsiniz.

Aslında kafayı fazla karıştırmaya gerek yok. Genel geçer çok önemli bir kural var Windows işletim sisteminde programlamada. "Pencere create etmiş her bir thread, ilgili pencerenin mesaj kuyruğunu tüketmelidir".

Bunun istisnası yoktur. Aksi durumda, beklenmedik durumlar (genellikle kilitlenmeler) oluşur. Bu neden ile; ana thread haricinde oluşturduğumuz thread'lerimiz içinde, bir pencere oluşturuyor isek (Form'da bir penceredir) bu pencerenin mesaj döngüsünü kesinlikle tüketmeliyiz.

 Bu arada thread'ler içinde gizli biçimlerde pencere create eden API'ler vardır. Bunlara da dikkat etmek gerekir. (Bunların en önemlisi, CoInitialize API'sidir. Sık kullanılır). İçinde pencere oluşturan thread'lerin beklenmesi için en uygun API MsgWaitForMultipleObject/Ex API'sidir.

  Thread'ler, uygulama penceresinin mesajlarını tüketen API'leri çağırmak(Application.ProcessMessages, PeekMessage vb) aslında; paralel programlamanın gücünden istifade etmeye çalışmaktır. Yıl 2018 ve biz hâla tek çekirdekli programlar geliştiriyor isek, hatayı biraz da kendimizde aramamız gerekir. Bu nedenler ile yoğun bir şekilde, tüm arkadaşlarımı korkulan multi-thread konseptine yaklaştırmaya gayret ediyorum tüm gücümle. Ancak sebebine anlam veremediğim çok kuvvetli bir direnç ile karşılaşıyorum her daim. Kimbilir belki ben iyi anlatamıyorum, önemine vurgu yapamıyorum. Bilemiyorum.

Birden fazla thread ile çalışmaya başladığınızda uygulamalarınız bir t zamanında çok daha fazla iş yapacak demektir. Programınız bir iş yaparken aynı anda bir başka iş daha yapabilecektir. (Aslında öyle değil tabii. Windows gerçek bir multithreaded işletim sistemi değildir. Sadece simüle eder.) Bunun faydası kime olacak peki ? Elbette programınızı kullanacak kullanıcılara. Amiyane tabir ile yağ gibi akan bir programınız olacak.

 Bu konu başlığı altındaki WaitMessage API'si de çağrıldığı thread'in mesaj kuyruğuna bir mesaj ulaşana kadar bekleme işini yapar. İlgili MSDN dökümanlarını inceleyenler göreceklerdir. MsgWaitForMultipleObjects API'si gerçekten de güçlü bir API'dir ve yapabildiklerini görünce; insanın içinde "onu kullanmalıyım" düşünceni oluşturur.

Herneyse, uzunca yazarak gözlerinizi ağrıttı isem affola.

@Tuğrul HELVACI uzun açıklamalarınız için teşekkürler, ama sanırım lafı uzatmayım diye kısa kesmem bazı detayların eksik kalmasına sebep olmuş.

Mesajı yazarken arada "event-driven" programcılıktan da bahsetmiş, ama sonradan mesaj uzun olunca silmiştim Smile Anlayacağınız, eğer event-driven programcılıktan bahsediyorsak gerçekten de Application.ProcessMessages kötü bir metod oluyor, çünkü o zaman event değil, fonksiyon bekliyorsunuz demektir. Bunun en güzel örneği Android işletim sistemi. Event-driven programcılık sayesinde UI bile ayrı bir thread'de çalışıyor ve Google bundan kesinlikle taviz vermiyor (Android işletim sisteminde ShowModal olmamasını sebebi de bu). Application.ProcessMessages aslında ana thread'e yanlış bir sorumluluk yüklemenin getirdiği bir kaçış fonksiyonu. Event-driven programcılıkta, ana thread bir işlem yapılacağı zaman, ilgili thread'i çalıştırıyor ve kendi iç parametrelerini buna göre güncelliyor. İlgili threadden mesaj geldiği zaman (illa mesaj değil, aslında bir event tetiklendiği zaman) gerekli işlemleri yapıyor. 

Benim açımdan Application.ProcessMessages'in kabul edilebileceği iki durum var:
1. İlk mesajımda da yazdığım gibi, program yazmak hızlı yapılan bir iş değil. Ama şartlar, müşteri, patron artık herhangi bir sebepten dolayı (itiraf ediyorum, sık sık da üşenmekten) hızlı yazmak gerekiyorsa Application.ProcessMessages bir çok dertten kurtarıyor. Kod kaliteli olmuyor ama zaten hızlı yazıyoruz Smile 
2. 3. parti API, SDK, kütüphane kullanıyorsanız işler sizin planladığınız gibi gitmeyebiliyor. Örneğin eskiden Skype API'si Windows mesajları üzerine kuruluydu (hala öyle mi bilmiyorum) ve karmaşık tasarımlarda (plug-in tabanlı ve Skype'in plug-in olarak çalışması gibi) Application.ProcessMessages işi kurtarabiliyor. Burada dikkat edilmesi gereken, asıl uygulamanın Skype referans alınarak tasarlanmamış olması. Yani plug-in'lerin Windows mesajlarını kullanması beklenmedik bir durum ve ciddi bir sürpriz.

Sonuç olarak, event driven programcılık seven birisi olarak Application.ProcessMessages fonksiyonuna özel duygular beslemiş olabilirim.

İyi çalışmalar
Cevapla
#39
Cevap bile "ders yap okut" cinsinden Smile Merak ettiğim bir şeyin sebebine ilişkin cevabını daha cümle arasında buldum. Bir çok şeyi dil bilsek de anlayamayabiliyoruz. İyi niyet esastır, bunun farkındayız. Teşekkürler.

(02-05-2018, Saat: 22:20)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: ... Bu neden ile; ana thread haricinde oluşturduğumuz thread'lerimiz içinde, bir pencere oluşturuyor isek (Form'da bir penceredir) bu pencerenin mesaj döngüsünü kesinlikle tüketmeliyiz.

 Bu arada thread'ler içinde gizli biçimlerde pencere create eden API'ler vardır. Bunlara da dikkat etmek gerekir. (Bunların en önemlisi, CoInitialize API'sidir. Sık kullanılır). İçinde pencere oluşturan thread'lerin beklenmesi için en uygun API MsgWaitForMultipleObject/Ex API'sidir.
Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif


Cevapla
#40
(02-05-2018, Saat: 23:32)Bahadir.Alkac Adlı Kullanıcıdan Alıntı:
(02-05-2018, Saat: 22:20)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: İyi akşamlar. Öncelikle kıymetli bilgilerinizi paylaştığınız için teşekkür ederim. Belirtmek isterim ki, ben bir çözüm aramıyorum. Amacım, önemli gördüğüm bu husus hakkında bir bilinç oluşmasını sağlamaya çalışmaktı.

Müsaadeniz ile yazdıklarınızın bir kısmına iştirak etmediğimi belirtmek isterim. "Sonsuza dek bekleme olmaz !" demişsiniz. INFINITE sonsuzluk anlamına gelse de sizin de bileceğiniz gibi esasen 49.7 güne tekabül eder. Bazen bir thread, başka thread'lerin işlerini tamamlamalarını beklemek durumunda kalır.Sırası ile yapılması gereken işler olabilir. Ya da bu tarz senaryolar çoğaltılabilir. Bu durumda, yapılacak işlerin ne kadar süreceği bilinmiyor ise INFINITE ile beklemekten başka bir çare yoktur.

 Elbette işlerin bitmesini beklemenin başka yolları da vardır. Örneğin pencereler arası mesajlaşma API'leri (PostMessage, SendMessage vb.) ya da callback mekanizmaları gibi. Ancak, bahse konu kernel senkronizasyon nesnelerinin beklenmesi son derece yaygın bir uygulama alanına sahiptir ve bunun sisteme de faydası olduğu yadsınamaz bir gerçektir. (Bir thread nonsignaled (işaretli olmayan) kernel nesnelerinden birisini beklemeye başladığında aslında işletim sistemi ilgili thread'i pause eder ve başka thread'leri işletmeye devam eder.)

Bu bağlamda, bu tarz bir beklemenin "tasarım hatası" ile ilişkilendirilmesini pek kabul edemiyorum.

Application.ProcessMessages çağrımına neden gıcık olduğunuzu, ona neden bu denli temkinli yaklaştığınızı bilmiyorum ama; Application.ProcessMessages altında yatan API'ler (GetMessage, TranslateMessage, DispatchMessage) olmadan Windows ortamında bir uygulamadan bahsedilemeyeceğini siz de benim kadar bilirsiniz.

Aslında kafayı fazla karıştırmaya gerek yok. Genel geçer çok önemli bir kural var Windows işletim sisteminde programlamada. "Pencere create etmiş her bir thread, ilgili pencerenin mesaj kuyruğunu tüketmelidir".

Bunun istisnası yoktur. Aksi durumda, beklenmedik durumlar (genellikle kilitlenmeler) oluşur. Bu neden ile; ana thread haricinde oluşturduğumuz thread'lerimiz içinde, bir pencere oluşturuyor isek (Form'da bir penceredir) bu pencerenin mesaj döngüsünü kesinlikle tüketmeliyiz.

 Bu arada thread'ler içinde gizli biçimlerde pencere create eden API'ler vardır. Bunlara da dikkat etmek gerekir. (Bunların en önemlisi, CoInitialize API'sidir. Sık kullanılır). İçinde pencere oluşturan thread'lerin beklenmesi için en uygun API MsgWaitForMultipleObject/Ex API'sidir.

  Thread'ler, uygulama penceresinin mesajlarını tüketen API'leri çağırmak(Application.ProcessMessages, PeekMessage vb) aslında; paralel programlamanın gücünden istifade etmeye çalışmaktır. Yıl 2018 ve biz hâla tek çekirdekli programlar geliştiriyor isek, hatayı biraz da kendimizde aramamız gerekir. Bu nedenler ile yoğun bir şekilde, tüm arkadaşlarımı korkulan multi-thread konseptine yaklaştırmaya gayret ediyorum tüm gücümle. Ancak sebebine anlam veremediğim çok kuvvetli bir direnç ile karşılaşıyorum her daim. Kimbilir belki ben iyi anlatamıyorum, önemine vurgu yapamıyorum. Bilemiyorum.

Birden fazla thread ile çalışmaya başladığınızda uygulamalarınız bir t zamanında çok daha fazla iş yapacak demektir. Programınız bir iş yaparken aynı anda bir başka iş daha yapabilecektir. (Aslında öyle değil tabii. Windows gerçek bir multithreaded işletim sistemi değildir. Sadece simüle eder.) Bunun faydası kime olacak peki ? Elbette programınızı kullanacak kullanıcılara. Amiyane tabir ile yağ gibi akan bir programınız olacak.

 Bu konu başlığı altındaki WaitMessage API'si de çağrıldığı thread'in mesaj kuyruğuna bir mesaj ulaşana kadar bekleme işini yapar. İlgili MSDN dökümanlarını inceleyenler göreceklerdir. MsgWaitForMultipleObjects API'si gerçekten de güçlü bir API'dir ve yapabildiklerini görünce; insanın içinde "onu kullanmalıyım" düşünceni oluşturur.

Herneyse, uzunca yazarak gözlerinizi ağrıttı isem affola.

@Tuğrul HELVACI uzun açıklamalarınız için teşekkürler, ama sanırım lafı uzatmayım diye kısa kesmem bazı detayların eksik kalmasına sebep olmuş.

Mesajı yazarken arada "event-driven" programcılıktan da bahsetmiş, ama sonradan mesaj uzun olunca silmiştim Smile Anlayacağınız, eğer event-driven programcılıktan bahsediyorsak gerçekten de Application.ProcessMessages kötü bir metod oluyor, çünkü o zaman event değil, fonksiyon bekliyorsunuz demektir. Bunun en güzel örneği Android işletim sistemi. Event-driven programcılık sayesinde UI bile ayrı bir thread'de çalışıyor ve Google bundan kesinlikle taviz vermiyor (Android işletim sisteminde ShowModal olmamasını sebebi de bu). Application.ProcessMessages aslında ana thread'e yanlış bir sorumluluk yüklemenin getirdiği bir kaçış fonksiyonu. Event-driven programcılıkta, ana thread bir işlem yapılacağı zaman, ilgili thread'i çalıştırıyor ve kendi iç parametrelerini buna göre güncelliyor. İlgili threadden mesaj geldiği zaman (illa mesaj değil, aslında bir event tetiklendiği zaman) gerekli işlemleri yapıyor. 

Benim açımdan Application.ProcessMessages'in kabul edilebileceği iki durum var:
1. İlk mesajımda da yazdığım gibi, program yazmak hızlı yapılan bir iş değil. Ama şartlar, müşteri, patron artık herhangi bir sebepten dolayı (itiraf ediyorum, sık sık da üşenmekten) hızlı yazmak gerekiyorsa Application.ProcessMessages bir çok dertten kurtarıyor. Kod kaliteli olmuyor ama zaten hızlı yazıyoruz Smile 
2. 3. parti API, SDK, kütüphane kullanıyorsanız işler sizin planladığınız gibi gitmeyebiliyor. Örneğin eskiden Skype API'si Windows mesajları üzerine kuruluydu (hala öyle mi bilmiyorum) ve karmaşık tasarımlarda (plug-in tabanlı ve Skype'in plug-in olarak çalışması gibi) Application.ProcessMessages işi kurtarabiliyor. Burada dikkat edilmesi gereken, asıl uygulamanın Skype referans alınarak tasarlanmamış olması. Yani plug-in'lerin Windows mesajlarını kullanması beklenmedik bir durum ve ciddi bir sürpriz.

Sonuç olarak, event driven programcılık seven birisi olarak Application.ProcessMessages fonksiyonuna özel duygular beslemiş olabilirim.

İyi çalışmalar

Cevap verme hakkımı yarına saklıyorum Smile
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla




Konuyu Okuyanlar: 1 Ziyaretçi