Makale Özeti

Threading uygulamalarda program içerisinde yarattığınız işçi threadleri askıya almanız ya da durdurmanız gerekecektir. .net framework 2x ile birlikte thread askıya alma ve geri çalışır duruma getirme metotları olan Thread.Suspend() ve Thread.Resume() iptal(deprecated) edilmiştir. Bunun yerine daha önceki örneklerde görülen senkronizasyon nesneleri ve sizin kontrol edeceğiniz durum bayrakları kullanılacaktır. Zaten dikkat ederseniz Windows forms ve threading örneğinde “TerminateThreads” ve “mrEvent” ile threadlerin işlemden çıkıp çıkmayacaklarını yada askıda kalıp kalmayacaklarını kontrol ediyorduk. Bu sebepden thread durdurma metodları olan Interrupt() ve Abort() metotlarını inceleyeceğiz.

Makale

C#.NET ve Threading (Thread durdurma ve askiya alma)

Thread Durdurma ve askıya alma

Threading uygulamalarda program içerisinde yarattığınız işçi threadleri askıya almanız ya da durdurmanız gerekecektir. .net framework 2x ile birlikte thread askıya alma ve geri çalışır duruma getirme metotları olan Thread.Suspend() ve Thread.Resume() iptal(deprecated) edilmiştir. Bunun yerine daha önceki örneklerde görülen senkronizasyon nesneleri ve sizin kontrol edeceğiniz durum bayrakları kullanılacaktır. Zaten dikkat ederseniz Windows forms ve threading örneğinde “TerminateThreads” ve “mrEvent”  ile threadlerin işlemden çıkıp çıkmayacaklarını yada askıda kalıp kalmayacaklarını kontrol ediyorduk.

Bu sebepden thread durdurma metodları olan Interrupt() ve Abort() metotlarını inceleyeceğiz.

Thread.Interrupt()

            Interrupt() metodu o an “wait”, “sleep” ya da” join” sebebi ile bloke durumda kalan bir thread’i bekleme durumundan çıkarmak için kullanılır. O anda bekleyen bir threadin Interrupt() metodunu çağırdığınızda ilgili thread içerisinde ThreadInterruptedException exception’ı oluşacaktır. Bu durumda programcı ilgili exception’ı yakalamalı ve gerekli işlemleri yapmalıdır. Eğer programcı ThreadInterruptedException exception’ı yakalamaz ise .net framework runtime hatayı yakalayacak ve thread’i durduracaktır.  Interrupt() metodu uygulanan thread o anda bekleme durumunda değil ise ThreadInterruptedException exception thread bekleme durumuna gelene kadar oluşmayacaktır. Eğer thread hiç bekleme durumuna gelmeden işini bitirecekse ThreadInterruptedException exception’unu hiç almayacaktır.

Bir örnek verelim

using System;
using System.Threading;

namespace ThreadStopping
{
    class Program
    {
        static void Main()
        {
            Worker worker = new Worker();
            ThreadStart job = new ThreadStart(worker.DoWork);
            Thread thread = new Thread(job);
            thread.Start();
            for (int i = 0; i < 3; i++)
            {
                Thread.Sleep(1000);
                thread.Interrupt();
            }
            thread.Join();
            Console.WriteLine();
            Console.WriteLine("Program bitti bir tuşa basınız.");
            Console.ReadKey();
        }
    }
    public class Worker
    {
        public void DoWork()
        {
            int intrCount = 1;
            while(true)
            {
                try
                {
                    Console.WriteLine("İşçi thread sonsuza kadar bekleyecek. Bekleme {0}.", intrCount);
                    Thread.Sleep(Timeout.Infinite);   
                }
                catch(Exception e)
                {
                    if (e is ThreadInterruptedException)
                    {
                        Console.WriteLine("\tInterrupt exception yakalandı. Yakalanma sayısı {0}.", intrCount);
                        if (intrCount == 3)
                        {
                            Console.WriteLine("\t\t{0}. interrupt denemesi. Thread sonlandırılıyor.", intrCount);
                            break;
                        }
                        intrCount++;
                    }
                }
            }
        }
    }
}

Örnek programımızın çıktısında görüldüğü üzere işçi thread üç defa bekleme durumundan çıkarılmaya çalışılmış ve 2 seferde bekleme durumundan çıkarılarak çalışmasına devam etmiş ama 3. seferde  kendi kendisini sonlandırmıştır.

Isçi thread sonsuza kadar bekleyecek. Bekleme 1.
        Interrupt exception yakalandi. Yakalanma sayisi 1.
Isçi thread sonsuza kadar bekleyecek. Bekleme 2.
        Interrupt exception yakalandi. Yakalanma sayisi 2.
Isçi thread sonsuza kadar bekleyecek. Bekleme 3.
        Interrupt exception yakalandi. Yakalanma sayisi 3.
                3. interrupt denemesi. Thread sonlandiriliyor.

Program bitti bir tusa basiniz.

 

Thread.Abort()

Thread.Abort()  metodu, metodun çağrıldığı thread’i sonlandırmak için kullanılır. Abort() metodu çağrıldığında ilgili thread içerisinde ThreadAbortException exception’ı oluşacaktır. Yalnız önemli bir detay, ThreadAbortException  exception’ı bir önceki  konuda gördüğümüz ThreadInterruptedException’ı gibi programcı tarafından yakalanmadığı takdirde runtime tarafından yakalanmaz. Sonlandırılmaya çalışılan thread içerisinden kontrollü bir şekilde çıkmak için ThreadInterruptedException exception’ı catch bloğu içerisinde yakalanmalı ya da thread içerisinde finally bloğu uygulanarak thread işini bitirdiğinde kullanılan kaynakları serbest bırakma ya da benzeri işlemleri yazılmalıdır.

Bir örnekle yapalım.

using System;
using System.Threading;
namespace ThreadAbort
{
    class Program
    {
        static void Main()
        {
            Worker worker = new Worker();
            ThreadStart job = new ThreadStart(worker.DoWork);
            Thread thread = new Thread(job);
            thread.Start();
            for (int i = 0; i < 3; i++)
            {
                Thread.Sleep(1000);
                thread.Abort();
            }
            thread.Join();
            Console.WriteLine();
            Console.WriteLine("Program bitti bir tuşa basınız.");
            Console.ReadKey();
        }
    }
    public class Worker
    {
        public void DoWork()
        {
            int abortCount = 1;
            try
            {
                while (true)
                {
                    try
                    {
                        Console.WriteLine("İşçi thread sonsuza kadar bekleyecek. Bekleme {0}.", abortCount);
                        Thread.Sleep(Timeout.Infinite);
                    }
                    catch (ThreadAbortException)
                    {
                        Console.WriteLine("\tAbort exception yakalandı. Yakalanma sayısı {0}.", abortCount);
                        if (abortCount < 3)
                        {
                            Thread.ResetAbort();
                            abortCount++;
                        }
                    }
                }
            }
            finally
            {
                Console.WriteLine("\t\t{0}. Abort denemesi. Thread sonlandırılıyor.", abortCount);
            }
        }
    }
}

 

Isçi thread sonsuza kadar bekleyecek. Bekleme 1.
        Abort exception yakalandi. Yakalanma sayisi 1.
Isçi thread sonsuza kadar bekleyecek. Bekleme 2.
        Abort exception yakalandi. Yakalanma sayisi 2.
Isçi thread sonsuza kadar bekleyecek. Bekleme 3.
        Abort exception yakalandi. Yakalanma sayisi 3.
                3. Abort denemesi. Thread sonlandiriliyor.

Program bitti bir tusa basiniz.

 

Uygulama çıktısında görüldüğü üzere örnek uygulama aynı bir önceki Interrupt örneğinde olduğu gibi 3. Abort isteğinde işçi thread  sonlanmıştır. Dikkat ederseniz bu programdada 1. Ve 2. Abort işleminde uygulama sonlanmıyor tam tersine çalışmaya devam ediyor. Bu özellik Thread.ResetAbort() metodu sayesinde sağlandı. Thread.ResetAbort() Abort metodu çağrılan thread içerisinde oluşan ThreadAbortException exception’unu iptal eder ve thread’in çalışmasına devam etmesini sağlar. Bu sayede 1. Ve 2. denemede thread’in çalışmaya devam etmesini sağlayabildik ama 3. Deneme ResetAbort() metudunu çağırmadığımız için thread finally bloğuna kadar düşüp kendisini sonlandırdı.