<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>Diyezon &#187; muteks</title> <atom:link href="http://www.diyezon.com/tag/muteks/feed/" rel="self" type="application/rss+xml" /><link>http://www.diyezon.com</link> <description>programlama sanatı...</description> <lastBuildDate>Tue, 24 Jan 2012 00:13:26 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <item><title>Delphi ile Thread(Kanal) Kullanımı &#8211; Bölüm 2</title><link>http://www.diyezon.com/delphi-ile-threadkanal-kullanimi-bolum-2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=delphi-ile-threadkanal-kullanimi-bolum-2</link> <comments>http://www.diyezon.com/delphi-ile-threadkanal-kullanimi-bolum-2/#comments</comments> <pubDate>Sat, 06 Oct 2007 17:44:45 +0000</pubDate> <dc:creator>Fatih Tolga Ata</dc:creator> <category><![CDATA[Delphi]]></category> <category><![CDATA[kanallar]]></category> <category><![CDATA[kritik bölgeler]]></category> <category><![CDATA[muteks]]></category><guid
isPermaLink="false">http://www.diyezon.com/?p=61</guid> <description><![CDATA[Bu bölümde kanalları nasıl eş zamanlı olarak çalıştırabileceğinizi göreceksiniz. Bunun için kritik bölgeler ve muteksler ile tanışacaksınız. Ayrıca kanal uyumlu olmayan VCL&#8217;in, kanallar ile nasıl kullanılabileceğini de göreceksiniz. Bununla beraber kanal kullanımındaki yaşanan bazı problemlere de değinmeye çalışacağız. Özellikle veritabanlarını kanallar ile kullanmada uyulması gereken püf noktalarına da değinmeye çalışacağız. Aslında bu bölüm gerçekten uzun [...]]]></description> <content:encoded><![CDATA[<p
align="justify">Bu bölümde kanalları nasıl eş zamanlı olarak çalıştırabileceğinizi göreceksiniz. Bunun için <strong>kritik bölgeler</strong> ve <strong>muteksler</strong> ile tanışacaksınız. Ayrıca kanal uyumlu olmayan VCL&#8217;in, kanallar ile nasıl kullanılabileceğini de göreceksiniz. Bununla beraber kanal kullanımındaki yaşanan bazı problemlere de değinmeye çalışacağız. Özellikle veritabanlarını kanallar ile kullanmada uyulması gereken püf noktalarına da değinmeye çalışacağız.</p><p
align="justify">Aslında bu bölüm gerçekten uzun oldu. Normalde VCL kullanımını üçüncü bir bölüme taşımayı düşünüyordum. Ama bu konuda istekler olunca birleştrip yayınlamayı düşüdüm. İçeride sizi iki sayfalık bir makale bekliyor. Bu yüzden sayfa sonunda bitti zannedip kapatmayın!</p><p
align="justify">Hazırsanız başlayalım.</p><p><span
id="more-61"></span></p><h1>Kanallar&#8217;ı Eş Zamanlı Olarak &Ccedil;alıştırmak</h1><p
align="justify">Kanallar ile uğraşırken karşılaşılan en büyük sorunlardan bir tanesi de şüphesiz kanalları ortak bir şekilde sorunsuz olarak çalıştırmaktır. Eminim kanallar ile uğraşan birisi bütün kanallar tarafından ortak olarak kullanılan bir kaynağa erişmede problemlerle karşı karşıya gelmiştir ve kanalları bir köşeye itmesine sebep olmuştur.</p><p
align="justify">Mesela şu veritabanı problemi size tanıdık gelecektir. Diyelim ki, iki adet kanalımız var ve bunlardan birincisi veritabanındaki bir kaydı açıp değişiklik yapmaya başladı. Sonra ikinci kanal aynı kaydın belli bölümlerinde düzenlemeler yaptıktan sonra veriyi kaydetti. Ardından birinci kanal, aynı verilerdeki değişikliğini bitirdi ve kaydetti. Birinci kanal, ikinci kanal&#8217;ın değişikliklerinden habersiz olduğundan ikinci kanalın yaptığı düzenlemeler de uçtu gitti.</p><p
align="justify">Burada okuduğunuz problem, normalde kanallar ve veritabanı ile uğraşan bir çok programcının başına gelmiş bir problemdir. Bununla birlikte sadece veritabanında değil bir çok noktada özellikle bir dosyayı, bir portu, bir DLL&#8217;i veya başka bir şeyi, kanalların <strong>ortak </strong>kullanmasında hep benzer sıkıntılarla karşılaşılmıştır. Bu gibi sıkıntıların ve problemlerin çözümü kanalları eş zamanlı kullanım için <strong>kritik bölgeler</strong> tanımlamak ya da <strong>muteksleri</strong> kullanmaktır. Bu iki yöntem de makalemizin konuları arasındadır.</p><h1>Kritik Bölgeler(Critical Sections)</h1><p
align="justify">Kritik Bölgeler -<em>ya da başka yerlerde görebileceğiniz gibi kritik kesimler, bölümler, vs..</em>- yukarıda anlatığımız problemdeki, birinci kanalın kaynağı kullanması esnasında ikinci kanalın bu kaynağa erişmesini <u>englelemek</u> için kullanılır. Birinci kanal işini yapıyorken, ikinci kanal&#8217;a çalışması için bir zaman dili ayrılmaz. Böylece birinci kanal işini bitirene kadar ikinci kanal çalıştırılmaz.</p><p
align="justify"> Bunun için örnek bir uygulamada yukarıdaki anlattığımız senaryolara benzer bir problem oluşturalım ve çözümünü aramaya çalışalım.</p><p
align="justify">Diyelim ki, iki adet kanalımız var ve bu kanallar bir döngünün her adımında bir dizi işlem gerçekleştiriyor. Ve bu gerçekleştirdikleri işlemler için ortak kullandıkları global olarak tanımlanmış bir değişken olsun. Meseleyi anlatabilmek için iki kanalında yaptığı işlemlerin sonucunun aynı olmasını sağlamak istiyorum. Böylece problem daha iyi anlaşılabilecek.</p><p
align="justify">Birinci kanal bir döngünün her adımında global değişkenimize teker teker harfler ekliyor ve sonuçta değişkenimizde bir yazı oluşuyor. Aynı işlemi ikinci kanalımız da yapıyor ve sonuç olarak birinci kanal ile aynı yazıyı üretiyorlar. Yanlız ikinci kanal harfleri teker teker eklemek yerine <u>ikişer ikişer</u> ekliyor. Ekleme işlemi çok hızlı olduğundan problemin oluşması için aralara <em>Sleep </em>rutinini ekleyerek işlemi birazcık yavaşlatıyoruz. Şimdi bu mantığımızı koda dökmeye başlayalım.</p></p><p
align="justify"> Yeni bir VCL uygulaması açalım ve bir adet button ekleyelim. Aşağıdaki gibi unitin var bloğunda global bir değişken tanımlayalım:</p><pre>
<pre class="brush: delphi">var
  Form1: TForm1;
  SonucYazi: string; //Global değişkenimiz</pre></pre><p
align="justify">Ardından buttonun OnClick olayını aşağıdaki gibi değiştirelim.</p><pre>
<pre class="brush: delphi">procedure TForm1.Button1Click(Sender: TObject);
var
  Kanal1ID, Kanal2ID: DWORD;
begin
  CreateThread(nil, 0, @Kanal1, nil, 0, Kanal1ID);
  CreateThread(nil, 0, @Kanal2, nil, 0, Kanal2ID);
end;</pre></pre><p
align="justify">Bu iki adet kanalımıza ait kanal fonksiyonlarını da aşağıdaki gibi oluşturalım:</p></p><pre>
<pre class="brush: delphi">procedure Kanal1;
procedure Kanal2;

...

implementation

...

procedure Kanal1;
var
  i: Integer;
begin
  for i := 0 to 10 do
  begin
    SonucYazi := SonucYazi + &#039;d&#039;;
    Sleep(10);
    SonucYazi := SonucYazi + &#039;i&#039;;
    SonucYazi := SonucYazi + &#039;y&#039;;
    SonucYazi := SonucYazi + &#039;e&#039;;
    Sleep(10);
    SonucYazi := SonucYazi + &#039;z&#039;;
    SonucYazi := SonucYazi + &#039;o&#039;;
    SonucYazi := SonucYazi + &#039;n &#039;;
    Sleep(10);
  end;
end;

procedure Kanal2;
var
  i: Integer;
begin
  for i := 0 to 10 do
  begin
    SonucYazi := SonucYazi + &#039;di&#039;;
    Sleep(10);
    SonucYazi := SonucYazi + &#039;ye&#039;;
    SonucYazi := SonucYazi + &#039;zo&#039;;
    Sleep(10);
    SonucYazi := SonucYazi + &#039;n &#039;;
  end;
end;</pre></pre><p
align="justify">Gördüğünüz gibi iki kanal fonksiyonu da aynı sonucu üretiyor. Ama sonucu üretme yolları farklı. Ayrıca iki kanal da peş peşe oluşturulup çalıştırılıyor. Forma bir adet daha button ekleyelim ve bize sonucu göstersin. Bunun için ikinci butonumuzun OnClick olayını aşağıdaki gibi düzenleyelim:</p><pre>
<pre class="brush: delphi">procedure TForm1.Button2Click(Sender: TObject);
begin
  ShowMessage(SonucYazi);
end;</pre></pre><p
align="justify">Bu programı çalıştırdıktan sonra ve kanalları birinci düğme ile çalıştırdıktan sonra sonuç yazının &quot;diyezon diyezon diyezon &#8230;&quot; gibi bir şey olmasını isteriz. Yani bir for döngüsünün bir adımı <u>tamamlanmadan</u> <em>SonucYazi </em>isimli global değişkene <u>müdahale</u> olmasını istemeyiz. Halbuki programı çalıştırdığınızda sonucun hiç de böyle olmadığını göreceğiz. <em>Kanal1</em> işini bitirip &quot;diyezon &quot; yazmadan <em>Kanal2</em> işe karışmış ve aralarda kendi harflerini eklemiştir. Hakeza bu, <em>Kanal2</em> için de geçerlidir. Yani <em>Kanal2</em>, döngünün bir adımını bitirip istenilen sonucu veremeden <em>Kanal1</em> global değişkenimize müdahale etmiştir.</p><p
align="justify">Burada verdiğimiz örnek biraz soyut kaçabilir. &Ccedil;ünkü yaptığımız işlemden sonuç olarak elimize bir şey geçmiyor. Ama karşılaşacağınız sorunlar hep bu tarzda sorunlardır. Karşılaştığınız sorunları verdiğimiz bu örnek ile kıyaslama yapabilirsiniz. Mesela biz bu örneğimizde işlem adımlarını yavaşlatmak için <em>Sleep</em> rutinini kullandık. Normal hayatta kanallar ile uğraşırken zaten yaptığımız işlemlerin adımları <em>Sleep</em> rutinini aratmamaktadır. Mesela bir veritabanı tablosunda <em>Edit</em> ve <em>Post</em> gibi metodları kullandığımızda belli bir miktar işlemin tamamlanmasını bekleriz. Bir de eğer sizde sonuç düzgün çıkıyorsa yine söylüyorum işlemciniz, bu makaleyi yazdığım sıralardaki işlemcimden hızlı demektir. Bu durumda <em>Sleep</em> rutinine verdiğimiz değerleri çok az miktarlarda artırmayı deneyin.</p><p
align="justify">Sadede gelelim ve problemi anladı isek şöyle bir soruyu kafamıza getirelim: Bir kanal belli bir işini bitirmeden önce diğer kanalların müdahalesini nasıl <u>engelleyebiliriz</u>?</p><p
align="justify">Cevabı zaten bu bölümün başında verdik. Bunun için belli yerleri <u>kritik bölge</u> ilan edeceğiz. Bir kanalda kritik bölge ilan ettiğimiz yerdeki kodlar çalışmaya başladığı sırada, diğer kanallardaki <strong><u>aynı</u></strong> kritik bölgedeki kodlar işletilmez ve bekler. Yani <strong>aynı kritik bölgeye sahip kanallardan aynı anda sadece bir bölgedeki kodlar çalıştırılabilir</strong>. Böylece diğer kanalların istenilmeyen müdahalesi engellenmiş olur.</p><p
align="justify">Bir Kritik bölge tanımlamak için bilmemiz gereken üç dört adet Windows apisi vardır.</p><p
align="justify"><font
face="Courier New"><strong>InitializeCriticalSection</strong></font>: Bu fonksiyon kritik bölge&#8217;yi temsil eden recordun ilk değerlerini atamakla sorumludur. Yani kritik bölgeyi kullanıma hazırlamaktadır. Genelde formun <em>OnCreate</em> olayında kullanılır.</p><p
align="justify"><font
face="Courier New"><strong>DeleteCriticalSection</strong></font>: Yukarıdaki fonksiyonun tam tersi olarak, bu fonksiyon da kritik bölgeyi ortadan kaldırır. Genelde formun <em>OnDestroy</em> olayına yerleştirilir.</p><p
align="justify"><font
face="Courier New"><strong>EnterCriticalSection</strong></font>: Bu fonksiyonu çalıştırdığınız satırdan itibaren kritik bölgenin başlangıcını belirtirsiniz. Yani Delphi&#8217;deki &quot;<strong><font
face="Courier New">begin</font></strong>&quot; kelimesi gibi düşünebilirsiniz.</p><p
align="justify"><font
face="Courier New"><strong>LeaveCriticalSection</strong></font>: Bu fonksiyon ise, çalıştırıldığı satırla kritik bölgeyi sınırlandırır. Yine Delphi&#8217;deki &quot;<font
face="Courier New"><strong>end</strong></font>&quot; ifadesine benzetebiliriz.</p><p
align="justify">Kritik bölgeyi temsil eden record ise <em>TRTLCriticalSection</em> tipindedir. Normalde Windows SDK yardım dosyalarında <em>LPCRITICAL_SECTION</em> şeklinde tanımlanmıştır. Ama Delphi ekibi bir çok windows yapısını tanımlarken bunlara &quot;<strong>T</strong>&quot; ile başlayan daha iyi okunur alias isimler vermişler. Her neyse&#8230;</p><p
align="justify"> Kritik bölgenin tanımlanması gayet basittir. Bir kritik bölgeyi işletim sistemine tanıtmak için <em>InitializeCriticalSection </em>fonksiyonunu kullanıyoruz. Kritik bölge ile işimiz bittiğinde de <em>DeleteCriticalSection </em>fonksiyonunu çağırmayı unutmuyoruz. Ardından kanal fonksiyonlarımızda kritik bölgeleri belirleyip <u>başına</u> <em>EnterCriticalSection </em>ve <u>sonuna</u> <em>LeaveCriticalSection </em>sonksiyonlarını koyuyoruz.</p><p
align="justify">Örneğimize dönelim ve kritik bölgeleri eklemeye başlayalım. Bizim müdahale istemediğimiz bölge, kanal fonksiyonlarındaki döngülerin her bir <u>adımıdır</u>. Yani teker teker veya ikişer ikişer ekleme yapılan kısımlarda bir adım işini bitirmeden başka bir kanalın global değişkenimize müdahalesini engellemek istiyoruz. Kısacası kritik bölgemiz bu örnekte, döngünün her bir adımı olmalıdır.</p><p
align="justify">İlk başta global olarak bir değişken daha tanımlayalım. Bu değişken bizim kritik bölgemizi temsil eden record olsun.</p><pre>
<pre class="brush: delphi">var
  Form1: TForm1;
  SonucYazi: string;
  BirinciKritikBolge: TRTLCriticalSection; //kritik bölgemizi temsil ediyor.</pre></pre><p
align="justify">Ardından formun <em>OnCreate </em>ve <em>OnDestroy </em>olaylarını aşağıdaki gibi değiştirelim.</p><pre>
<pre class="brush: delphi">procedure TForm1.FormCreate(Sender: TObject);
begin
  InitializeCriticalSection(BirinciKritikBolge);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  DeleteCriticalSection(BirinciKritikBolge);
end;</pre></pre><p
align="justify">Eğer başka kritik bölgeler de tanımlamış iseniz bunları da <em>InitializeCriticalSection </em>ve <em>DeleteCriticalSection </em>fonksiyonlarını kullanarak oluşturmalı ve silme işlemlerini gerçekleştirmelisiniz. Bizim örneğimizde bir adet kritik bölge yeterlidir.</p><p
align="justify">Şimidi kanal fonksiyonlarında bahsettiğimiz yerleri kritik bölge olarak ilan edelim.</p><pre>
<pre class="brush: delphi">procedure Kanal1;
var
  i: Integer;
begin
  for i := 0 to 10 do
  begin
    EnterCriticalSection(BirinciKritikBolge); //BirinciKritikBolge başlangıcı
    SonucYazi := SonucYazi + &#039;d&#039;;
    Sleep(10);
    SonucYazi := SonucYazi + &#039;i&#039;;
    SonucYazi := SonucYazi + &#039;y&#039;;
    SonucYazi := SonucYazi + &#039;e&#039;;
    Sleep(10);
    SonucYazi := SonucYazi + &#039;z&#039;;
    SonucYazi := SonucYazi + &#039;o&#039;;
    SonucYazi := SonucYazi + &#039;n &#039;;
    Sleep(10);
    LeaveCriticalSection(BirinciKritikBolge); //BirinciKritikBolge bitişi
  end;
end;

procedure Kanal2;
var
  i: Integer;
begin
  for i := 0 to 10 do
  begin
    EnterCriticalSection(BirinciKritikBolge); //BirinciKritikBolge başlangıcı
    SonucYazi := SonucYazi + &#039;di&#039;;
    Sleep(10);
    SonucYazi := SonucYazi + &#039;ye&#039;;
    SonucYazi := SonucYazi + &#039;zo&#039;;
    Sleep(10);
    SonucYazi := SonucYazi + &#039;n &#039;;
    LeaveCriticalSection(BirinciKritikBolge); //BirinciKritikBolge bitişi
  end;
end;</pre></pre><p
align="justify">Yapacağımız başka bir işlem kalmadı. Programı çalıştırıp deneybiliriz. Sonucun &quot;diyezon diyezon diyezon &#8230;&quot; gibi düzgün olduğunu göreceğiz. &Ccedil;ünkü Kritik bölge tanımlayarak sadece bir kanalın kritik bölgesini çalıştırmış olduk. Böylece bir kanal global <em>SonucYazi </em>değişkeni ile uğraşırken diğer kanal buna müdahale edemeyecektir.</p><p
align="justify">Burada bir adet kritik bölge tanımladık. Sizler ihtiyaca göre projelerinizde bir çok kritik bölge tanımlayabilirsiniz. Ayrıca kritik bölgelerin birbirinden <u>bağımsız </u>hareket ettiğini de aklınızdan çıkarmayın. Bazen karıştırılan nokta bu kısım olabiliyor. Mesela bu örneğimizde bir adet kritik bölge mevcut ama iki farklı yapılan iş var.</p><p
align="justify">Gördüğünüz gibi kanalları eş zamanlı olarak çalıştırmak o kadar da zor değilmiş. Tek yaptığımız bell bölgeleri kritik bölge olarak ilan etmek. Şimdi yeni bir kavramla daha tanışalım.</p><h1>Muteksler(Mutex)</h1><p
align="justify">İngilizce&#8217; de, <strong>mut</strong>ual ve <strong>ex</strong>clusive kelimelerinin birleşiminden meydana gelmiştir. Dilimizde ise müşterek ve seçkin kelimeleri bu kelimeleri karşılamaktadır. Programlama terminolojisinde ise, sadece tek işlemdeki değil <strong>birden fazla</strong> işlemdeki kanalları eş zamanlı olarak kullanılmasını sağlayan bir tekniktir.</p><div
align="justify">Muteksler, çalışma mantığı olarak kritik bölgelere benzerler fakat fazladan bir özellik olarak sadece aynı işlem yani sadece aynı uygulamada değil <strong>başka </strong>uygulamadaki kanallar ile eş zamanlı olarak çalışmayı da sağlarlar.</div><p
align="justify"><strong>Bir mutekse aynı anda sadece bir tek kanal sahip olabilir. </strong>Literatürde, bu mutekse, bir kanal sahip olduğunda, muteksin kanal tarafından &quot;<strong>tetiklendiği</strong>&quot; ya da &quot;<strong>tutulduğu</strong>&quot; söylenir. Aynı şekilde eğer kanal bu mutekse sahip deiğilse muteks &quot;<strong>serbestir</strong>&quot; ya da &quot;<strong>tetiklenmemiştir</strong>&quot; tabirleri kullanılır.</p><p
align="justify">Şu an kafanızda mutekslerin ne olduğuna dair somut bir düşünce oluşmamış olabilir. Ama bölümün sonuna kadar okuduğunuzda neyin ne olduğuna dair bir fikir oluşacağına eminim.</p><p
align="justify">Bir muteks, <em>CreateMutex </em>fonksiyonu ile oluşturulur. Bu fonksiyonun tanımlanması ve açıklaması aşağıdadır.</p><pre>
<pre class="brush: delphi">function CreateMutex(lpMutexAttributes: PSecurityAttributes;
  bInitialOwner: BOOL;
  lpName: PChar): THandle;</pre></pre><p
align="justify"><font
face="Courier New"><strong>lpMutexAttributes</strong></font>: Muteksin güvenliği ile ilgli parametredir. Bu parametreye <strong>nil </strong>girerek varsayılan güvenlik özelliklerini ayarlamış oluyoruz.</p><p
align="justify"><font
face="Courier New"><strong>bInitialOwner</strong></font>: Kanalın bu mutekse sahip olup olmadığını ya da yukarıda bahsettiğimiz gibi muteksin tetiklenip tetiklenmeyeceğini belirler. True ya da False giriyoruz. Genelde muteksi programın ana kanalında oluşturduğumuzdan, ana kanalın mutekse sahip olmasını istemeyiz. Bu yüzden genelde bu parametreye False gireriz.</p><p
align="justify"><font
face="Courier New"><strong>lpName</strong></font>: Eğer farklı işlemler bu mutekse erişecekse bu muteksimize bir isim vermemiz gerekmektedir. Buraya <strong>nil</strong> de girebilirisiniz. Bu durumda isimsiz bir muteksimiz olur.</p><p
align="justify">Bu fonksiyon eğer muteksi oluşturabilirse çıktı olarak muteksin handle numarasını dönderir. Eğer muteks oluşmamış ise <strong>0</strong> değerini çıktı olarak verir.</p><p
align="justify">Muteksleri, kritik bölgeler gibi düşünebilirsiniz. Kritik bölge oluşturmak için kullandığımız <em>InitializeCriticalSection</em> fonksiyonu yerine <strong>CreateMutex</strong> fonksiyonunu, kritik bölgenin başlangıcını belirten <em>EnterCriticalSection</em> yerine <strong>WaitForSingleObject</strong> fonksiyonunu, kritik bölgenin bitişini bildiren <em>LeaveCriticalSection</em> fonksiyonu yerine de <strong>ReleaseMutex</strong> fonksiyonunu kullanıyoruz. <strong>CloseHandle </strong>ile de CreateMutex ile oluşan muteksin handle&#8217;ını kapatmayı da unutmuyoruz.</p></p><p
align="justify">İlk önce bir muteks oluşturalım.</p><pre>
<pre class="brush: delphi">birmuteks := CreateMutex(nil, False, &#039;ornekmuteks&#039;);</pre></pre><p
align="justify">Ardından kritik bölgeyi oluşturduğumuz yerlerdeki fonksiyonları muteksin fonksiyonları ile yer değiştiriyoruz. Şimdilik sadece <em>Kanal1</em> için örnek verelim.</p><pre>
<pre class="brush: delphi">procedure Kanal1;
var
  i: Integer;
begin
  for i := 0 to 10 do
  begin
    WaitForSingleObject(birmuteks, INFINITE); //Muteksin tetiklenmesini bekle
    SonucYazi := SonucYazi + &#039;d&#039;;
    Sleep(10);
    SonucYazi := SonucYazi + &#039;i&#039;;
    SonucYazi := SonucYazi + &#039;y&#039;;
    SonucYazi := SonucYazi + &#039;e&#039;;
    Sleep(10);
    SonucYazi := SonucYazi + &#039;z&#039;;
    SonucYazi := SonucYazi + &#039;o&#039;;
    SonucYazi := SonucYazi + &#039;n &#039;;
    Sleep(10);
    ReleaseMutex(birmuteks); //Muteksi serbest bırak.
  end;
end;</pre></pre><p
align="justify">Şimdi muteksin ne olduğuna dair kafanızda bir şeyler şekillenmeye başlmamıştır. &Ccedil;ünkü kodlara baktığımızda <em>WaitForSingleObject </em>fonksiyonu  bir şeyleri bekliyor ve <em>ReleaseMutex </em>ise bir şeyi serbest bırakıyor. <em>WaitForSingleObject</em>, &quot;<strong>tek bir nesne için bekle</strong>&quot; gibi bir manası var. Esas yaptığı görev, birinci parametresinde verilen handle numarasına göre bir muteksi <u>beklemektir</u>. İkinci parametresinde ise ne kadar bekleyeceğini belirliyoruz. Bu örneğimizde <em>INFINITE </em>(sonsuz) girmekle, bir muteks tetiklenene kadar bekleyeceğini belirttik. Bu parametreye, en fazla ne kadar bekleneceğini milisaniye şeklinde girebilirsiniz.</p><p
align="justify">Muteksi anlamada genelde verilen örnek ve bence en iyi örnek bayrak yarışıdır. Bayrak yarışlarında <u>bir şeritte ancak bir</u> koşucu koşabilir. <u>Bayrağı alan koşmaya başlar</u>. Bir şeritte, bayrağa sahip <u>olmayan</u>, koşabilmek için bayrağı <u>beklemesi</u> gerekmektedir. Böyelece her bir şeritte sadece bir yarışçı koşabilir.</p><p
align="justify">Aynen bunun gibi, kanallar çalışabilmek için mutekse sahip olmaları gerekmektedir. <u>Mutekse sahip olan koşmaya yani çalışmaya başlar</u>. Mutekse sahip olmayan, muteksin kendisine gelmesini <u>bekler</u>. Bir hatırlatma olarak, önceki paragraflarda sahip olmanın tetiklemek olduğundan bahsetmiştik.</p><p
align="justify">İşte <em>WaitForSingleObject </em>ile muteksin bu kanalımıza gelmesini beklemiş oluyoruz. Ve bunu örneğimizde, <em>INFINTE </em>yani sonsuz süre kadar bekliyoruz. Ve muteksle işimiz bittiğinde diğer kanalların kullanabilmesi için muteksi <em>ReleaseMutex </em>ile serbest bırakıyoruz. Ve yine tekrar ediyorum &quot;<strong>Bir mutekse aynı anda sadece bir tek kanal sahip olabilir.</strong>&quot;</p><p
align="justify"><em>CreateMutex </em>ile oluşturduğumuz muteksin handle&#8217;nı formun <em>OnDestroy </em>olayında <em>CloseHandle </em>ile kapatmayı da unutmuyoruz. Yani kritik bölgelerde yaptığımız <em>DeleteCriticalSection </em>yerine</p><pre>
<pre class="brush: delphi">CloseHandle(birmuteks);</pre></pre><p
align="justify">gibi bir şey yazmalıyız.</p><p
align="justify">Bu örneği, makaleyi fazla uzatmasın diye, burada tüm kodlarını yazmayacağım. Muteks örnek projesini <a
href="http://www.diyezon.com/wp-content/uploads/File/post61/muteks1.rar">buradan</a> indirebilirsiniz.</p><p
align="justify">Eğer tek bir muteks değil de bir den fazla muteksi tetiklemesini bekelemek istersek ne olacak? Bu durumda <strong>WaiıtForMultipleObjects </strong>fonksiyonunu kullanacağız. <em>WaitForSingleObject </em>tek bir muteksi beklerken <em>WaitForMultipleObject </em>fonksiyonu birden fazla muteksi beklemektedir. Kullanım aynı olduğu için bununla ilgili bir örnek yapmayacağım. Bu fonksiyon ile iligli tek söyleyebileceğim şey ikinci parametrede beklediğiniz mutekslerin handle&#8217;larını dizi şeklinde girmeniz olacaktır.</p><h2>Başka İşlemlerden Mutekslere Sahip Olma</h2><p
align="justify">Dediğimiz gibi, mantık olarak mutekslerin kritik bölgelerden tek farkı, başka program ve işlemlerdeki kanallar ile ortak ve eş zamanlı çalışmaya izin vermesidir. Bunun için muteksimize bir isim vermemiz gerektiğini söylemiştik. İşte bu ismi kullanarak başka bir işlem muteksin handle numarasını alabilir. Gerisinde de <em>WaitForSingleObject </em>ve <em>ReleaseMutex </em>fonksiyonlarında bu handle numarasını kullanabiliriz. Yani mevcut bir muteksin handle numarasını alabilmek için:</p><pre>
<pre class="brush: delphi">birmuteks := OpenMutex(0, False, &#039;ornekmuteks&#039;);</pre></pre><p
align="justify">dememiz yeterli. Bunu yukarıdaki örneğimizde <em>CreateMutex </em>yerine kullanabilirsiniz. Ama unutmamanınız gereken nokta bunun ile <strong>mevcut </strong>bir muteksin handle numarasını alırız. Eğer muteks <em>CreateMutex </em>ile hiç oluşturulmamış ise bu fonksiyon <strong>0</strong> değerini dönderir.</p><p
align="justify"><em>OpenMutex </em>fonksiyonunun parametreleri <em>CreateMutex </em>ile aynı olduğundan burada fazladan bir açıklama yapmayacağım.</p><p
align="justify">Bu konuda bir örnek yapmak isterseniz yukarıda verdiğimiz örneği iki uygulamaya bölebilirsiniz. <em>Kanal1</em>&#8216;i birinci uygulamada, <em>Kanal2</em>&#8216;yi de ikinci uygulamada oluşturursunuz. Ve ikisinde de <em>OnCreate</em> olayında şöyle bir şey girersiniz:</p><pre>
<pre class="brush: delphi">var
  BirMuteks: THandle;
.....
procedure TForm1.OnCreate(....);
begin
  BirMuteks := OpenMutex(0, False, &#039;ornekmuteks&#039;);
  if BirMuteks = 0 then
    BirMuteks := CreateMutex(nil, False, &#039;ornekmuteks&#039;);</pre></pre><p
align="justify">Kısaca burada yaptığımız işlem eğer &quot;ornekmuteks&quot; isminde bir mutex henüz oluşturulmamış ise oluşturuyoruz.</p><p
align="justify">Bu şekilde iki veya daha fazla sayıda işlem tek bir muteks üzerinde kanallarını eş zamanlı olarak çalıştırabilirler. Bu örneği kendiniz yapmaya çalışın. Gerçi <a
href="http://www.diyezon.com/wp-content/uploads/File/post61/muteks2.rar">burada</a> yapılmışı var <img
src='http://www.diyezon.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . Ama lütfen indirip incelemeden önce kendiniz yapmayı deneyin.</p><p>&#8212;</p></p><p
align="justify">İşte size iki adet yöntem. Ve ikisi de windows programlamada çok sık kullanılmaktadır. Kanalları beraber çalıştırmak istediğinizde, istrer muteks kullanın isterseniz kritik bölge tanımlayın. Her ikisinin de tanımlanması ve kullanılması çok kolay. Kafanızdaki &quot;kanal kullanmak çok zordur&quot; düşüncesini birinci bölümde aştığınızı düşünüyorum. Buraya kadar olan kısım ile de &quot;kanalları eş zamanlı çalıştırmak zordur&quot; düşüncesini yendiğinizi zannediyorum.</p><p
align="justify">Peki muteks ve kritik bölge arasında tercih yapmak gerekirse hangisini tercih etmeliyiz. Bence performans açısından pek fark olmaz. Seçim noktanız şu olmalı. Eğer, tek bir işlemden değil de bir çok işlemden yani bir çok programdan oluşan bir gurubun kanalları ortak ve eş zamanlı kullanmasını düşünüyorsak kesinlikle muteks kullanmalıyız. Aksi durumda yani eş zamanlı çalışacak olan kanallar sadece tek bir işlemde bulunuyorlarsa o zaman seçim size kalmış. Hangisi rahatınıza gidiyorsa onu kullanabilirsiniz.</p><p
align="justify">Şimdi farklı bir konuya geçiş yapalım. Hazırsanız ikinci sayfadan devem edelim.</p> ]]></content:encoded> <wfw:commentRss>http://www.diyezon.com/delphi-ile-threadkanal-kullanimi-bolum-2/feed/</wfw:commentRss> <slash:comments>19</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using memcached
Page Caching using memcached
Database Caching 1/9 queries in 0.013 seconds using memcached
Object Caching 290/301 objects using memcached

Served from: www.diyezon.com @ 2012-02-08 11:38:13 -->
