22 Nisan 2015 Çarşamba

Thread'i Durdurmak

Giriş
Thread'i kolay ve temiz bir şekilde durdurmak her programlama dilinde sıkıntıdır. Aşağıda notlarım var.

Worker Thread
Bu tür thread'leri durdurmanın en temiz yolu, kuyruğa özel bir job eklemek. Örnek
void SimpleWorkQueue::tellAllThreadsToStop()
{
    std::unique_lock<std::mutex> locker(lock);
    stopping = true;

    for(std::thread& thread: workers)
    {
        work.push_back([](){ throw TerminateThread(); });
    }
}


// Now our main thread loop.
// looks like this.
// Note: We can remove 'finished' from everywhere.
void SimpleWorkQueue::workerAction()
{
    while(true)
    {
        std::function<void()> item = getNextWorkItem();
        try
        {
            item();
        }
        catch(TerminateThread const& e)
        {
            break;
        }
        catch(...)
        {
        }
    }
}

WIN32
TerminateThread() asla kullanılmamalı. Win32 ile bir thread sınıfı gelmediği için durdurma kontrolünü kendimiz yazmalıyız. Thread'i başlatmadan önce bir event yaratırız. Event'ler aynı bir bayrak gibi kullanılabilir.
HANDLE hevent_killme = CreateEvent(...);
Daha sonra bu event thread'e geçilir.

static DWORD WINAPI thread_callback (LPVOID param)
{
  ...
  while(WaitForSingleObject(hevent_killme, 0) != WAIT_OBJECT_0)
  {
    // do stuff
  }

  return 0;
}
Thread'i durdurmak isteyen event'i tetikler.
void killthread (void)
{
  SetEvent(hevent_killme);
  WaitForSingleObject(hthread_the_thread, INFINITE);
  CloseHandle(hevent_killme);
  CloseHandle(hthread_the_thread);
} 

Java
Thread.stop
Bu metod depricate edilmiş ve kullanılmamalı. Sebebi şu:

This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior.

Thread.Interrupt
Bir thread'i durdumanın en kolay ve temiz yolu Thread.Interrupt () metodunu çağırmak.

An interrupt is an indication to a thread that it should stop what it is doing and do something else. It's up to the programmer to decide exactly how a thread responds to an interrupt, but it is very common for the thread to terminate.


Thread.Interrupt Ne Yapar?
Metod aslında sadece bir bayrağı kaldırır. Metod tamamen işbirliği esasına dayanır. Bir thread asla bir başka thread'i durdurmaya zorlayamaz. Diğer thread'in de gönül rızası göstererek durmayı kabul etmesi gerekir.


Interrupts this thread. First the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.

If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.

If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.

If none of the previous conditions hold then this thread's interrupt status will be set.

Thread.interrupted
Çalışan thread döngü içinde interrupted() metodunu ile durdurulmasının talep edilip edilmediğini kontrol etmeli. Metodun açıklaması şöyle. Thread bu metodu çağırdıktan sonra bayrak indirilir.

Eğer thread kendi içinde halen bu bayrağı kontrol ediyorsa, yine thread içinde Thread.currentThread.interrupt() ile bayrağı tekrar kaldırmak gerekebilir.

static boolean interrupted(): Tests whether the current thread has been interrupted.
Basit bir örnek
public void run()
{
    while(!Thread.interrupted)
    {
     ...
    }
}

Thread.isInterrupted
Eğer başka bir thread'in interrupt edilip edilmediğini anlamak istersek isInterrupted() metodu kullanılır

boolean isInterrupted(): Tests whether this thread has been interrupted.

InterruptedException
Eğer interrupt edilen thread bir nesne üzerinde bloke olmuş bekliyorsa InterruptedException alır.

Thread.isInterrupted true dönerse InterruptedException atılması öneriliyor. Ancak interrupt edildiğimizi anladıktan sonra neden exception atmak lazım anlamadım.
if (Thread.interrupted()) throw new InterruptedException(); 


Hiç yorum yok:

Yorum Gönder