İlginizi Çekebilir
  1. Ana Sayfa
  2. Java
  3. Interrupt Nedir? Hardware Interrupts – Software Interrupts

Interrupt Nedir? Hardware Interrupts – Software Interrupts

Interrupt Nedir ? Interrupt türkçeye kesme olarak çevrilmiş bir terimdir. Yazılım veya donanım kaynaklı gerçekleşen bir olayın (Network kartının buffer’ının dolması, harddisk’in IO işlemini tamamlaması, aritmetik işlemler sırasında sıfıra bölme hatasının oluşması) işlemciye acil olarak bildirilerek islenmesi gerektiği “durumlarda” üretilir. Bu “durumlar” işlemci uzerinde islenmekte olan process’in (süreç) bitmesini bekleyemeyecek acil ve kritik oldukları için bekletilmeden islenmelidirler. işlemci bir interrupt istemi aldığı zaman, yapmakta olduğu işi bir kenara bırakır (Context Switch; işlemci kaldığı yeri işaretler) gelen interrupt’in handler fonksiyonunu bir tablo vasıtası ile belirler, gerekli işlemeyi yapar ve interrupt’ı üreten cihaza işlemin tamamlandığını ve interrupt üretmeyi artık bırakmasını söyler. İlgili cihaz interrupt üretmeyi bırakır ve işlemci öncesinde yapmakta olduğu ise geri döner.

Donanım Interruptlari (Hardware )

Bilgisayar cevre birimleri (Harrdisk, Network Karti, Fare, Klavye, Dokunmatik Ekran vs) durumları ile ilgili bir değişiklik olduğunda işlemciye bu yeni durumu bildirmek için interruptlari kullanırlar. Bu durum değişikliği donanımın yaptığı bir isin tamamlanması, kullanıcının donanım ile etkileşimi yada ansızın beliren kritik bir hata olabilir. Klavyede bir tusa basılması, farenin hareket ettirilmesi, dokunmatik ekrana kullanıcının dokunması, pilin kritik seviyeye düşmesi örnek olarak verilebilir. Donanım kaynaklı interruptlar işlemci ve ana kart uzerinde bulunan bir iç haberleşme ağı uzerinden elektriksel olarak işlemciye iletilir, işlemci işletim sistemi tarafından tanımlanmış alt-bellek uzayında bulunan bir tablo uzerinden (interrupt table) gelen interrupt’in ilgili handlerini (isleyici) çağırarak interrupt’i isler. İşlemci interrupt’ı işlemeyi tamamladıktan sonra interrupt’ı üreten donanıma bir sinyal göndererek interrupt’ı üretmeyi kesmesini ister ilgili donanım bu sinyali aldığında interrut üretmeyi bırakır. Diğer bir ifade ile işlemci interrupt’ı isledikten sonra interrupt durumunu resetler.

Donanım Interrupt’ları Maskable ve Non-Maskable olmak üzere ikiye ayrılır, Maskable interrupt’lar ignore edilebilir, yani işlemcinin görmezden gelmeye programlanabildiği interruptlardir. Non-Maskable Interruptlar ise işlemcinin ignore edemeyeceği ve mutlaka cevap vermesi gereken interruptlardir. Non-Maskable interruptlar genellikle kritik donanım arızalarında üretilir.

( Interrupts)

interruptlari işlemci içerisinde özel bir durumun oluşması (sıfıra bölme hatası) veya instruction set içerisindeki özel bir kodun execute edilmesi ile üretilirler. Yazılım interruptlari yazılımın sistem çağrılarını kullanması (trap) ve/veya kernel ile haberleşmesini sağlamak için diğer bir ifade ile user space uygulamaların kernel space çağrıları gerçekleştirmesi için de kullanılan bir mekanizmadır.

Örnek olarak dosyaya yazan bir program geliştirdiğinizi düşünelim, open() veya close() çağrıları bir software interrupt üretecek, execution user space’den kernel space’e geçecektir. İşletim sistemi interrupt’ı ilgili interrupt handleri çağırarak handle edecek ve sizin yerinize disk uzerinde ilgili dosyayı açarak Open File Table’a ilgili file descriptor’ı koyacak ve execution tekrar kernel space’den user space’e devredecek programımız da icrasına devam edecektir.

Java’da Interruptlar

Java’da interruptlar yukarida açıklanan interrupt kavramından farklı çalışmaktadır. Kısa bir ifade ile Java’da bir Thread nesnesi interrupt() metodu çağrılarak interrupt edilir. Ancak bu işlem bir trap (yazılımsal interrupt) yada donanımsal bir sinyal üretmez, thread nesnesi içerisinde bulunan boolean bir değişkenin değeri true’ya setlenir. Java’da Thread nesnesini interrupt etmeniz aslında onun yaptığı işi bırakmasını ve sonlanmasını istediğimizi Thread nesnesine söylememizin bir yoludur. Başka bir deyişle responsive programlama için oluşturulmuş bir uyarma (notification) yöntemidir. Interrupt edilen Thread sonlanıp sonlanmama konusuna kendisi karar verir, interrupt ettiğimiz bir Thread sonlanmak istemiyor ise sonlanmayacak çalışmaya devam edecektir 🙂 Bu konuyu bir örnek ile açalım:

package com.rhtech.interrupt;
public class t1 extends Thread {

@Override

public void run() {

try {

while (true) {

sleep(1000);
System.out.println(“Processing …”);

}
} catch (InterruptedException exc) {
System.out.println(“Interrupted: ” + exc);

}
}

}

package com.rhtech.interrupt;
public class Main {

public static void main(String[] args) throws Exception {

t1 t1 = new t1();
t1.start();

Thread.sleep(2000);

t1.interrupt();

Thread.sleep(2000);

System.out.println(t1.isInterrupted());

System.out.println(“The end!”);

}
}

t1 nesnesini Main threadin içerisinde oluşturup bir sure çalışmasına izin verdikten sonra t1’i interrupt ediyoruz. Diğer bir ifade ile t1 nesnesinin boolean interrupt değişkenini true’ya setliyoruz. Programın çıktısı aşağıdaki şekilde:

Processing …

Processing …

Interrupted: java.lang.InterruptedException: sleep interrupted

false

The end!

Process finished with exit code 0

1. t1 threadi 2 cycle boyunca çalışmış. Her cycle sonunda 1000 ms uykuda beklemiş.

2. Main thread içerisinden t1 threadini 2 saniye sonra interrupt ediyoruz.

3. t1 threadi çalışma döngüsünü interruptedException atarak kapatıyor.

4. t1 threadinin interrupted bayrağını kontrol ediyoruz -> FALSE

5. Program icrası sonlanıyor.

Program çıktısını incelediğimiz zaman iki ayrıntı dikkate değer

1. t1’i interrupt ettiğimiz halde interrupt bayrağı neden false ?

2. t1 interrupt edildiğini nasıl anladı ?

Yazının başında donanım interruptlarini anlatırken, donanımın interrupt sinyalini işlemci interrupt’ı handle ettikten sonra, işlemcinin istemesi ile kapadığını hatırlayacaksınız, burada da benzer bir süreç var. Sleep çağrısı interrupt değişkeninin true değerini aldığını anladığında InterruptedException üretiyor ve interrupt’ı işlediği için interrupted değişkenini false değerine çekiyor. Java’da var olan interruptedException üreten tüm blocking çağrılar (wait, sleep vs) aynı şekilde davranıyorlar. Bu bilgi ışığında çıktıyı incelediğimizde herşey yerli yerine oturuyor 🙂

Şimdi farklı bir implementasyon uzerinden devam edelim, InterruptedException üreten Blocking bir çağrı kullanmadığımız durumu göz önüne alalım:

package com.rhtech.interrupt;
public class t2 extends Thread {

@Override

public void run() {

while (!isInterrupted()) {

System.out.println(“working …”);
}

System.out.println(“Terminating execution interrupted ” + isInterrupted());
}
}

Bu sefer t2 nesnemizin thread döngüsü içerisinde InterruptedException üreten bir çağrı kullanmıyoruz, t2 interrupt değişkenini kontrol eden bir döngü içerisinde işlemlerini gerçekleştiriyor. Döngünün kırılması ancak t2’nin interrupt bayrağını true değerini setlenmesi ile mümkün, dolayısı ile beklentimiz t2’yi interrupt ettiğimizde döngünün sonlanıp Terminating execution interrupted : true mesajının ekrana basılması.

package com.rhtech.interrupt;
public class Main2 {
public static void main(String[] args) throws Exception {
t2 t2 = new t2();
t2.start();
Thread.sleep(10);
t2.interrupt();
t2.join();
System.out.println(“t2 interrupted status: ” + t2.isInterrupted());
}
}

Main içerisinde t2 threadimizi oluşturup çalıştırıyoruz, çalışabilmesi için kendisine 10 ms veriyor ve interrupt ediyoruz, join çağrısı ile t2’nin sonlanmasını bekliyor ve t2’nin interrupt değişkeni değerini ekrana yazıyoruz. Program çıktımız aşağıdaki şekilde:

working …

working …

working …

Terminating execution interrupted true

t2 interrupted status: false

Çıktıyı inceleyelim,

1. Terminating execution interrupted true

2. t2 interrupted status: false

1 numaralı mesaj t2 içerisinden yazılan mesajımız, kodu incelediğimizde bunun beklenen çıktı olduğunu görüyoruz. Interrupt değişkeni true değerinde.

2 numaralı mesajimiz ise main içerisinden basılan mesaj ancak burada interrupt bayrağının false değerinde olduğunu görüyoruz ki bunun olabilmesi için t2‘nin interrupt durumunun bir şekilde resetlenmis olması gerekiyor. Mesajı basan kod satiri ile t2‘yi interrupt ettiğimiz kod satırı arasında t2.join çağrısı hemen dikkat çekiyor. t2.join çağrısı blocking bir çağrı ve javadoc’u incelediğimizde metod imzasının aşağıdaki şekilde olduğunu görüyoruz.

/**

* Waits for this thread to die.

*

* <p> An invocation of this method behaves in exactly the same

* way as the invocation

*

* <blockquote>

* {@linkplain #join(long) join}{@code (0)}

* </blockquote>

*

* @throws InterruptedException

* if any thread has interrupted the current thread. The

* <i>interrupted status</i> of the current thread is

* cleared when this exception is thrown.

*/
public final void join() throws InterruptedException {

join(0);
}

t2.join() çağrısı interrupt değişkenini gerçekten resetliyor ancak küçük bir sorunumuz var, t2.join() çağrısını Main thread içerisinden yapıyoruz, dolayısı ile Main thread interrupt edilirse bu metodun InterruptedException atması ve Main threadin interrupted değişkenini resetlemesini beklememiz gerekirdi. Bizim kodumuzda ise t2‘nin interrupted değişkeni false‘a setlenmiş durumda. Kodu aşağıdaki şekilde değiştirip tekrar icra etmek olan biteni daha iyi anlamamızı sağlayacak:

package com.rhtech.interrupt;
public class Main2 {

public static void main(String[] args) {

try {

t2 t2 = new t2();
t2.start();

Thread.sleep(10);

t2.interrupt();

System.out.println(“t2 interrupted status: ” + t2.isInterrupted() + ” t2 state: ” + t2.getState());

Thread.sleep(20);

System.out.println(“t2 interrupted status: ” + t2.isInterrupted() + ” t2 state: ” + t2.getState());

} catch (InterruptedException exc) {
System.out.println(exc);

}
}

}

Kodu bu hali ile tekrar icra ediyor ve çıktıyı inceliyoruz:

working …

working …

Terminating execution interrupted true

t2 interrupted status: true t2 state: RUNNABLE

t2 interrupted status: false t2 state: TERMINATED

t2.join çağrısını Thread.sleep(20) ile değiştirdik ayrıca Thread state’imizide loglarımıza bastık çıktıyı detaylı bir şekilde incelediğimizde şunu görüyoruz:

1. t2.interrupt() çağrısının hemen arkasından interrupt durumunu bastığımızda interrupt bayrağının setlenmiş olduğunu görüyoruz. Ayrıca Thread’in hala RUNNABLE state’de olduğunu loglarımızdan anlıyoruz.

2. 20 ms bekledikten sonra tekrar ayni logu bastığımızda interrupted değişkeninin false‘a setlendigini ve Thread state’inin TERMINATED state’e çekildiğini görüyoruz.

JVM’in Thread lifecycle’ini yöneten kodu, Thread sonlandıktan sonra internal bir metod icrası ile belli başlı değişkenleri resetliyor. Interrupted değişkeni de bu resetleme işleminden nasibini alıyor gibi görünüyor.

Thread Interrupt mekanizmasını ve olası kullanım alanlarını toparlarsak:

Java’da Interrupt mekanizması bir threadin diğer bir thread’den sonlanmasını nazikçe istemek için kullanılan bir haberleşme yöntemi, ayrıca SDK bu mekanizmayı destekleyecek Interrupted değişkenini göz önünde bulunduran pek çok blocking çağrı içeriyor (join, wait, sleep etc). Blocking çağrıların yer almadığı durumlarda interrupted değişkenini poll ederek icra akışının kontrol edilmesi diğer bir kullanım yöntemi.

Aşağıda bir Thread’in icrasını kontrol etmek için kullanılan alternatif bir yaklaşım görebiliriz, burada görüldüğü üzere volatile
isRunning değişkeni akışın sonlanmasını kontrol etmek için koda eklenmiş.

package com.rhtech.interrupt;
public class t3 extends Thread {

private volatile boolean isRunning = true;
@Override

public void run() {

while (isRunning) {

// do processing

}

}


public void setRunning(boolean running) {

isRunning = running;

}
}

Interrupt mekanizmasını kullanarak aynı implementasyon aşağıdaki şekilde yapılabilir, görüldüğü gibi senkronizasyon ve yeni değişken ekleme ihtiyacı olmadan aynı poll işlemini interrupt mekanizması ile Thread Safe olarak gerçekleştirmek mümkün.

package com.rhtech.interrupt;
public class t2 extends Thread {

@Override

public void run() {

while (!Thread.currentThread().isInterrupted()) {

System.out.println(“working …”);
}

System.out.println(“Terminating execution interrupted ” + isInterrupted());
}
}

Ancak başka threadler tarafından bir threadin interrupt değişkenine erişmek ve bu değişkeni kontrol amaçlı kullanmak JVM’in interrupted değişkenine Thread state geçişlerinde (Runnable -> Terminated) müdahale etmesi sebebi ile reliable görünmüyor.

Bu konuyla ilgili sorularınızı https://forum.mshowto.org linkini kullanarak ulaşacağınız forum sayfamızda sorabilirsiniz.

Referanslar

www.mshowto.org

 

TAGs : Yazilim Interruptlari, , , , , Interrupts, yazilim, software,

Yorum Yap

Yazar Hakkında

Rıdvan Özaydın, lisans eğitimini Karadeniz Teknik Üniversitesi Bilgisayar Mühendisliği bölümünde, yüksek lisans eğitimini ise İstanbul Teknik Üniversitesi Bilgisayar Bilimleri bölümünde tamamlamıştır. Yazılım dünyasına üniversitenin ilk yıllarında aldığı C eğitimi ile başlamış, sektörün önde gelen firmalarında Java teknolojileri üzerine çalışmış, şu anda da Thales’de yazılım mühendisi olarak görev almaktadır.

Yorum Yap