Senkron & Asenkron ve MultiThread Programlama -7 — Thread Local Storage & Timers

Alperen Öz
5 min readSep 7, 2024

--

Thread Local Storage (TLS) & Timers

Thread Local Storage (TLS)

Thread Local Storage , C# ve diğer programlama dillerinde, her bir thread’in kendi özel veri alanına sahip olmasını sağlayan bir mekanizmadır.

Her thread, TLS kullanarak kendi özel veri değerlerini saklayabilir ve bu değerlere diğer thread’lerin erişimi olmaz. Bu özellikle çoklu iş parçacıklı (multi-threaded) uygulamalarda kullanışlıdır çünkü thread’ler arası veri bütünlüğünü korumak ve karşılaşabilecekleri race-condition durumlarını önlemek için tasarlanmıştır.

Thread Local Storage’in Amacı ve Avantajları:

  1. Amacı:
  • Thread Local Storage, her bir thread’in kendi bağlamında veri saklamasını sağlamak amacıyla kullanılır. Bu sayede her thread, kendi iş parçacığı içinde özel veriye sahip olabilir ve bu veriye diğer thread’ler erişemez.

2. Avantajları:

  • Veri Bütünlüğü: TLS, thread’ler arasında veri bütünlüğünü korumayı sağlar. Bir thread’in değiştirdiği veri, sadece o thread için geçerli olur ve diğer thread’ler üzerinde herhangi bir etkisi olmaz.
  • Performans: Özellikle threadler arası paylaşılan verilere erişimin sık olduğu durumlarda, TLS kullanarak veri erişimi daha hızlı ve verimli hale getirilebilir. Bu, race-condition durumlarını ve senkronizasyon maliyetlerini azaltabilir.
  • Kod Sağlığı ve Güvenliği: TLS, kodun daha düzenli ve daha az hata eğilimli olmasını sağlar çünkü thread’ler arasında veri paylaşımı daha kontrollüdür. Bu da programın güvenliğini ve performansını artırır.

ThreadStatic Attribute

ThreadStatic attribute , C# dilinde bir alanın veya değişkenin, her bir thread için ayrı bir örneğinin oluşturulmasını sağlayan bir işaretlemedir.

Bu attribute kullanıldığında, her thread kendi özel kopyasını saklar ve diğer thread’lerin bu değere erişimi olmaz. Bu attribute sadece static alanlar için kullanılır ve static bir alanın thread’e özgü veri olarak davranmasını sağlar.

[ThreadStatic]
static int x = 0;
private static void Main(string[] args)
{
Thread thread1 = new(() =>
{
while (x < 10)
Console.WriteLine($"Thread1 {++x}");
});

Thread thread2 = new(() =>
{
while (x < 10)
Console.WriteLine($"Thread2 {++x}");
});

Thread thread3 = new(() =>
{
while (x < 10)
Console.WriteLine($"Thread3 {++x}");
});

thread1.Start();
thread2.Start();
thread3.Start();
}

//ThreadStatic attribute olmadan output;

//Thread1 1
//Thread1 4
//Thread1 5
//Thread1 6
//Thread1 7
//Thread2 2
//Thread2 9
//Thread2 10
//Thread3 3
//Thread1 8

//ThreadStatic attribute'u ile output;

//Thread2 1
//Thread1 1
//Thread3 1
//Thread3 2
//Thread1 2
//Thread1 3
//Thread1 4
//Thread3 3
//Thread3 4
//Thread3 5
//Thread3 6
//Thread1 5
//Thread2 2
//Thread2 3
//Thread1 6
//Thread1 7
//Thread1 8
//Thread1 9
//Thread1 10
//Thread3 7
//Thread3 8
//Thread2 4
//Thread3 9
//Thread2 5
//Thread2 6
//Thread2 7
//Thread2 8
//Thread2 9
//Thread2 10
//Thread3 10

Örnekte görüldüğü üzere x değişkeni ThreadStatic attribute’u ile işaretlenmiş, bunun sonucu olarak, thread1, thread2 ve thread3 bu ortak değişkeni kullanmasına rağmen ThreadStatic ile işaretlendiği için, her biri x nesnesini kendi local storage’inde oluşturmuş ve kendi içerisinde x nesnesi üzerindeki işlemini ayrı ayrı yapmıştır.

ThreadStatic attribute’u, modern C# programlamada yerine daha güçlü ve esnek ThreadLocal<T> sınıfı tercih edilir. Bu sınıf, ThreadStatic'e benzer bir işlev sağlar ancak daha fazla esneklik ve güvenlik sunar.

ThreadLocal<T> class

ThreadLocal sınıfı, ThreadStatic attribute’una göre daha esnek bir davranış sergileyerek, hem static hem de instance field’ları için Thread- Local Storage sağlamaktadır.

Ayrıca ThreadLocal default değer de tanımlanabilmesine olanak sağlamaktadır.

ThreadLocal<int> x = new(() => 0);
Thread thread1 = new(() =>
{
while (x.Value < 10)
Console.WriteLine($"Thread1 {++x.Value}");
});

Thread thread2 = new(() =>
{
while (x.Value < 10)
Console.WriteLine($"Thread2 {++x.Value}");
});

Thread thread3 = new(() =>
{
while (x.Value < 10)
Console.WriteLine($"Thread3 {++x.Value}");
});

thread1.Start();
thread2.Start();
thread3.Start();

//Thread1 1
//Thread2 1
//Thread2 2
//Thread1 2
//Thread1 3
//Thread1 4
//Thread1 5
//Thread1 6
//Thread1 7
//Thread1 8
//Thread1 9
//Thread1 10
//Thread3 1
//Thread3 2
//Thread2 3
//Thread2 4
//Thread2 5
//Thread2 6
//Thread2 7
//Thread2 8
//Thread2 9
//Thread3 3
//Thread2 10
//Thread3 4
//Thread3 5
//Thread3 6
//Thread3 7
//Thread3 8
//Thread3 9
//Thread3 10

GetData & SetData Metotları

  • TLS yaklaşımını yansıtabilmenin bir diğer yolu iste GetData & SetData metotlarının kullanımıdır. Bu metotlar verileri thread’lere özgü slot adı verilen alanlarda depolar ve oradan okurlar.
  • Slot tanımlamak için LocalDataStorageSlot nesnesi kullanılmaktadır.
static LocalDataStoreSlot localDataStoreSlot = Thread.GetNamedDataSlot("x");
static int X
{
get
{
var data = (int?)Thread.GetData(localDataStoreSlot);
return data is null ? 0 : data.Value;
}
set => Thread.SetData(localDataStoreSlot, value);
}

static void Main(string[] args)
{
Thread thread1 = new(() =>
{
while (X < 10)
Console.WriteLine($"Thread1 {++X}");
});

Thread thread2 = new(() =>
{
while (X < 10)
Console.WriteLine($"Thread2 {++X}");
});

Thread thread3 = new(() =>
{
while (X < 10)
Console.WriteLine($"Thread3 {++X}");
});

thread1.Start();
thread2.Start();
thread3.Start();
}

Timer Sınıfı

Timer’lar Nedir?

Timer’lar, belirli bir zaman aralığıyla tekrar eden görevleri programlamak için kullanılan araçlardır. Yazılım geliştirme sürecinde, belirli periyodik görevleri otomatik olarak yürütmek için sıkça kullanılırlar. Örneğin, düzenli olarak veri yedekleme, zamanlanmış bildirimler gönderme veya periyodik sistem bakım görevleri gibi senaryolarda timer’lar devreye girer.

.NET framework, farklı ihtiyaçlara göre özelleştirilmiş çeşitli timer sınıfları sunar. Bu timer’lar, farklı senaryolar ve kullanım durumları için optimize edilmiştir. İki ana kategoriye ayrılabilirler: Multi-threaded Timer’lar ve Single-threaded Timer’lar. Bu kategoriler, timer’ların hangi thread’lerde çalıştığı ve nasıl kullanıldıkları ile ilgilidir.

.NET Timer Türleri

.NET framework, farklı senaryolar için çeşitli Timer sınıfları sunar. Bunlar:

  1. System.Threading.Timer
  2. System.Timers.Timer
  3. System.Windows.Forms.Timer
  4. System.Windows.Threading.DispatcherTimer

Bu Timer’lar, multi-threading ve single-threading işlemleri desteklemek üzere tasarlanmıştır.

Multi-threaded Timer’lar

Multi-threaded Timer’lar, birden fazla thread’in aynı anda çalışmasına olanak tanır ve bu thread’ler arasında senkronizasyonu sağlar. Özellikle arka planda çalışacak ve UI güncellemelerinden bağımsız olacak işlemler için idealdirler.

System.Threading.Timer

System.Threading.Timer, basit bir zamanlayıcıdır ve arka planda belirli aralıklarla çalıştırılması gereken işlemler için kullanılır. Bu Timer, Thread Pool kullanarak görevleri yürütür, bu nedenle performans açısından oldukça etkilidir.

Örnek Kullanım:

using System;
using System.Threading;

class Program
{
static void Main()
{
Timer timer = new Timer(Callback, null, 0, 2000);
Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
}

private static void Callback(object state)
{
Console.WriteLine("Tick: {0}", DateTime.Now);
}
}

System.Timers.Timer

System.Timers.Timer, System.Threading.Timer sınıfını sarmalar ve ek özellikler sunar. Özellikle, zamanlayıcı olaylarını doğrudan işlemek için tasarlanmıştır ve daha kapsamlı olay tabanlı (event-driven)programlama imkanı sağlar.

Örnek Kullanım:

using System;
using System.Timers;

class Program
{
static void Main()
{
Timer timer = new Timer(2000); // 2 seconds interval
timer.Elapsed += OnTimedEvent;
timer.AutoReset = true;
timer.Enabled = true;

Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
}

private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
Console.WriteLine("Tick: {0}", e.SignalTime);
}
}

Single-threaded Timer’lar

Single-threaded Timer’lar, genellikle UI uygulamalarında kullanılır ve yalnızca tek bir thread üzerinde çalışır. Bu, özellikle kullanıcı arayüzü elemanlarının güncellenmesi gereken senaryolar için uygundur. System.Windows.Forms.Timer ve System.Windows.Threading.DispatcherTimer single-thread Timer mekanizmasında kullanılan timer sınıfı türleridir.

System.Windows.Forms.Timer

System.Windows.Forms.Timer, Windows Forms uygulamaları için özel olarak tasarlanmış bir Timer sınıfıdır. Bu Timer, UI thread'inde çalışır ve doğrudan kullanıcı arayüzü elemanlarını güncelleyebilir.

System.Windows.Threading.DispatcherTimer

System.Windows.Threading.DispatcherTimer, WPF uygulamaları için kullanılan bir Timer sınıfıdır. Bu Timer, Dispatcher thread'inde çalışır ve WPF kullanıcı arayüzü elemanları ile etkileşimde bulunabilir.

System.Threading ve System.Timers Namespace’leri

  • System.Threading: System.Threading namespace'i, temel threading işlemleri ve senkronizasyon nesneleri sağlar. System.Threading.Timer bu namespace altında yer alır ve basit zamanlayıcı işlemleri için kullanılır.
  • System.Timers: System.Timers namespace'i, olay tabanlı zamanlayıcıları destekler ve System.Threading.Timer sınıfını sarmalar. Ek olarak, daha fazla özellik ve kolaylık sağlar. System.Timers.Timer bu namespace altında yer alır ve daha kapsamlı timer işlemleri için kullanılır.

Kaynak: Gençay Yıldız — Asenkron & Multithread Programlama

--

--