Makale Özeti

Threadleri bekletmek, durdurmak, önceliklendirmek

Makale

C# ile Threadleri Yönetmek:
 

Önceki makalede C# ile thread yaratarak uygulamamızı nasıl çok threadli olarak çalıştırabileceğimizi görmüştük. Bu makalede yarattığımız threadleri yönetmek için kullanabileceğimiz metodlara göz atacağız.
 

Threadleri Uyutmak:


Threadimiz çalışırken bir süre beklemesini de isteyebiliriz, bunu Sleep metodunu istediğimiz bekleme süresiyle çağırarak kullanarak yapıyoruz.

Önceki makaledeki örneğimizdeki Say1 metodunu değistirelim ve  sayarken her 5 sayıda bir 5 milisaniye beklemesini isteyelim.
 

 public void Say1(){

                  for(int i =0;i<100;i++){

                        Console.WriteLine("Say1:"+i.ToString());

                        if((i%5)==0){

                              Console.WriteLine("Say1: Ben biraz dinleneyim...");

                              Thread.Sleep(5);

                        }

                  }

            }


Programın çıktısı şöyle oldu:
 

Threadleri çalıştırdım, işim bitti...

Say2:0
Say2:1
Say2:2
Say2:3
Say2:4
Say2:5
Say2:6
Say2:7
Say2:8
Say2:9
Say2:10
Say2:11
Say2:12
Say2:13
Say2:14
Say2:15
Say2:16
Say2:17
Say1:0
Say1: Ben biraz dinleneyim...
Say2:18
Say2:19
Say2:20
Say2:21
Say2:22
...

 

Threadleri durdurmak, çalıştırmak:
 

Thread kendi kendini yukarıdaki şekilde beklemeye alabiliyor. Dışarıdan threadi kontrol etmeyi ise, Suspend ve Resume metodlarını kullanarak yapabiliyoruz. Suspend metodu, threadin durumunu değiştirerek threadi durdurur. Resume metodu ise threadin durumunu değiştirerek threadin çalışmaya başlamak üzere işaretler.

Yalnız threadleri yönetmek için Suspend ve Resume metodlarının kullanımı risklidir, ve tavsiye edilmemektedir. Çünkü bir threadi durdurduğunuzda o an o threadin ne yapıyor olduğunu bilemezsiniz, thread kendi elinde tuttuğu kaynakları da bırakamıyor olacağından programınızda sorunlara neden olabilir.
 

Threadleri öldürmek:
 

Threadimizi çalıştırmaya başladıktan bir süre sonra, threadimizi artık çalıştırmak istemiyorsak, thread sınıfının Abort metodunu kullanarak threadimizi öldürebiliriz.

Abort metodu çağırıldığında, çalışan threadde, çalışan threadin de öldürüldüğünden haberinin olması ve gerekeni yapabilmek için bir hata oluşturulur.

Şimdi programımız sadece Say1 metodunu gösteren thread1’i çalıştırsın ve 50 milisaniye bekledikten sonra da threadi öldürsün. Say1 metodunu da öldürüldüğünü anlayacak şekilde değiştirelim.
 

            public void ThreadleriCalistir(){

                        Thread thread1 = new Thread(new ThreadStart(Say1));

                        thread1.Start(); 

                        // 50 milisaniye bekleyeyim              

                        Thread.Sleep(50);

                        // bu kadar calistigin yeter

                        thread1.Abort();

                        thread1.Join();

                        Console.WriteLine("Güle Güle");

                  }

            public void Say1()

            {

                  try

                  {

                        for(int i =0;i<10000;i++)

                        {

                              Console.WriteLine("Say1:"+i.ToString());

                        }

                  }

                  catch(ThreadAbortException exception)

                  {

                        Console.WriteLine("Say1: Olduruldum...");

                  }

            }


Bu programın çıktısı da şöyle:
 

Say1:0
Say1:1
Say1:2
Say1:3
...
Say1:259
Say1:260
Say1:261
Say1: Olduruldum...
Güle Güle
 

Sayan threadimiz 50 msde 261e kadar saymayı başarmış, sonra threadden abort etmesi istenince o da bu hatayı yakalamış, ve threadin çalışması sona ermiş.


Threadleri önceliklendirmek:
 

Threadler paralel çalıştıkları düşünülse de , tek CPU’lu ortamda aslında threadler sıralanarak, ve her threade sırayla belirli zamanlar verilerek çalıştırılır. Böyle bir ortamda biz elimizdeki threadlerden birini veya birkaçını önceliklendirerek, örneğin kullanıcı önyüzüne sonuçları basmak gibi önemli işlerimizin, bekletilmeden yapılmasını sağlayabiliriz.

Threadleri thread sınıfına ait Priority özelliğine değer atayarak önceliklendirebiliriz. Atayabileceğimiz değerler yüksekten düşüğe doğru şunlardır:

     - Highest
- AboveNormal
- Normal
- BelowNormal
- Lowest

Varsayılan öncelik derecesi Normal’dir.

Şimdi bir örnekle ele alalım. Yine 0’dan 99’a kadar sayan 3 metodumuz olsun, bunlardan bir tanesine yüksek öncelik verelim, ve en son onu başlatalım:
 

using System;
using
System.IO;
using System.Threading; 

namespace Threadler2

{

      class Sinifim

      {

            static void Main(string[] args)

            {

                  Sinifim s =new Sinifim();

                  s.ThreadleriCalistir();

            }

            public void ThreadleriCalistir(){

               Thread thread1 = new Thread(new ThreadStart(Say1));

                  Thread thread2 = new Thread(new ThreadStart(Say2));

                  Thread thread3 = new Thread(new ThreadStart(Say3));

 

                  thread1.Priority = ThreadPriority.AboveNormal;

                  thread2.Priority = ThreadPriority.Normal;

                  thread3.Priority = ThreadPriority.Normal;

                  thread3.Start();

                  thread2.Start();

                  thread1.Start();

 

                  thread1.Join();

                  thread2.Join();

                  thread3.Join();

           

            }

            public void Say1()

            {

                  for(int i =0;i<100;i++)

                  {

                        Console.WriteLine("Say1:"+i.ToString());

                  }

            }

            public void Say2()

            {

                  for(int i =0;i<100;i++)

                  {

                        Console.WriteLine("Say2:"+i.ToString());

                  }

            }

            public void Say3()

            {

                  for(int i =0;i<100;i++)

                  {

                        Console.WriteLine("Say3:"+i.ToString());

                  }

            }

      }

}

 

Programın çıktısı:
 

Say1:1
Say1:2
Say1:3

...

Say1:99
Say2:0
Say2:1
Say2:2
...

Say2:27
Say2:28
Say2:29
Say3:0
Say3:1
Say3:2
Say3:3
Say3:4

...

 

Önceliği yüksek olduğu için önce Say1 i çalıştıran threadimizi çalıştırdı, o bittikten sonra diğer iki threadimize zamanı paylaştırdı.


Arkaplan Threadleri:
 

C#’da iki tur thread vardır, önplan(Foreground) threadleri ve arkaplan(Background) threadleri. Bunlar çalışması arasındaki farklılık programın kapanmasıyla ilgilidir.

Eğer programda çalışan önplan threadi hiç kalmazsa uygulamaya son verilir, ve uygulamada bulunan arkaplan threadleri de ThreadAbortException gönderilerek kapanmaya zorlanır.

Dolayısıyla uygulama kapandığında kapanmasını istediğimiz threadleri Arkaplan threadi olarak tanımlamalıyız, tersinin olmasını istiyorsak, yani threadimiz işini bitirmeden uygulamanın sona ermesini istemiyorsak threadimizi önplan threadi olarak tanımlamalıyız.

Bir tanımlama yapmadığımızda yarattığımız threadlerin Önplan threadleri olduğu varsayılır.
 


Bu makalede çalıştırdığımız threadleri yönetebilmek için neler yapabileceğimizi gördük. Sonraki makalede threadlerimizi senkronize bir şekilde çalıştırabilmemizi sağlayan monitor sınıfını inceleyeceğiz.

İyi Çalışmalar,

Onur Ağın
onur@onura.net