D Programlama - Eşzamanlılık

Eşzamanlılık, bir programın aynı anda birden fazla iş parçacığı üzerinde çalışmasını sağlamaktır. Eşzamanlı bir programa örnek, aynı anda birçok istemciye yanıt veren bir web sunucusudur. Eşzamanlılık, mesaj iletimi ile kolaydır, ancak veri paylaşımına dayalıysa yazmak çok zordur.

İş parçacıkları arasında aktarılan verilere mesaj denir. Mesajlar, herhangi bir türde ve herhangi bir sayıda değişkenden oluşabilir. Her iş parçacığının, mesajların alıcılarını belirtmek için kullanılan bir kimliği vardır. Başka bir iş parçacığını başlatan herhangi bir iş parçacığı, yeni iş parçacığının sahibi olarak adlandırılır.

D'de Konu Başlatma

Spawn () işlevi parametre olarak bir gösterici alır ve bu işlevden yeni bir evre başlatır. Bu işlev tarafından gerçekleştirilen tüm işlemler, çağırabileceği diğer işlevler de dahil olmak üzere, yeni iş parçacığında yürütülecektir. Sahip ve çalışan, sanki bağımsız programlarmış gibi ayrı ayrı çalışmaya başlarlar.

Misal

import std.stdio; 
import std.stdio; 
import std.concurrency; 
import core.thread;
  
void worker(int a) { 
   foreach (i; 0 .. 4) { 
      Thread.sleep(1); 
      writeln("Worker Thread ",a + i); 
   } 
}

void main() { 
   foreach (i; 1 .. 4) { 
      Thread.sleep(2); 
      writeln("Main Thread ",i); 
      spawn(≈worker, i * 5); 
   }
   
   writeln("main is done.");  
}

Yukarıdaki kod derlendiğinde ve çalıştırıldığında, önceki bölümde oluşturulan dosyayı okur ve aşağıdaki sonucu verir -

Main Thread 1 
Worker Thread 5 
Main Thread 2 
Worker Thread 6 
Worker Thread 10 
Main Thread 3 
main is done. 
Worker Thread 7 
Worker Thread 11 
Worker Thread 15 
Worker Thread 8 
Worker Thread 12 
Worker Thread 16 
Worker Thread 13
Worker Thread 17 
Worker Thread 18

D'deki Diş Tanımlayıcıları

Genel olarak modül düzeyinde mevcut olan thisTid değişkeni her zaman geçerli iş parçacığının kimliğidir. Ayrıca spawn çağrıldığında threadId'i alabilirsiniz. Aşağıda bir örnek gösterilmiştir.

Misal

import std.stdio; 
import std.concurrency;  

void printTid(string tag) { 
   writefln("%s: %s, address: %s", tag, thisTid, &thisTid); 
} 
 
void worker() { 
   printTid("Worker"); 
}
  
void main() { 
   Tid myWorker = spawn(&worker); 
   
   printTid("Owner "); 
   
   writeln(myWorker); 
}

Yukarıdaki kod derlendiğinde ve çalıştırıldığında, önceki bölümde oluşturulan dosyayı okur ve aşağıdaki sonucu verir -

Owner : Tid(std.concurrency.MessageBox), address: 10C71A59C 
Worker: Tid(std.concurrency.MessageBox), address: 10C71A59C 
Tid(std.concurrency.MessageBox)

D'de Geçen Mesaj

Send () işlevi mesajlar gönderir ve ReceOnly () işlevi belirli tipte bir mesajı bekler. PrioritySend (), take () ve ReceTimeout () adında başka fonksiyonlar da vardır ve bunlar daha sonra açıklanacaktır.

Aşağıdaki programın sahibi, çalışanına int türünde bir ileti gönderir ve double türünde bir worker (işçi) öğesinden bir ileti bekler. İş parçacığı, sahibi negatif bir int gönderene kadar ileri geri ileti göndermeye devam eder. Aşağıda bir örnek gösterilmiştir.

Misal

import std.stdio; 
import std.concurrency; 
import core.thread; 
import std.conv;  

void workerFunc(Tid tid) { 
   int value = 0;  
   while (value >= 0) { 
      value = receiveOnly!int(); 
      auto result = to!double(value) * 5; tid.send(result);
   }
} 
 
void main() { 
   Tid worker = spawn(&workerFunc,thisTid); 
    
   foreach (value; 5 .. 10) { 
      worker.send(value); 
      auto result = receiveOnly!double(); 
      writefln("sent: %s, received: %s", value, result); 
   }
   
   worker.send(-1); 
}

Yukarıdaki kod derlendiğinde ve çalıştırıldığında, önceki bölümde oluşturulan dosyayı okur ve aşağıdaki sonucu verir -

sent: 5, received: 25 
sent: 6, received: 30 
sent: 7, received: 35 
sent: 8, received: 40 
sent: 9, received: 45

D'de Bekleyerek Geçen Mesaj

Bekleyerek geçen mesajın basit bir örneği aşağıda gösterilmiştir.

import std.stdio; 
import std.concurrency; 
import core.thread; 
import std.conv; 
 
void workerFunc(Tid tid) { 
   Thread.sleep(dur!("msecs")( 500 ),); 
   tid.send("hello"); 
}
  
void main() { 
   spawn(&workerFunc,thisTid);  
   writeln("Waiting for a message");  
   bool received = false;
   
   while (!received) { 
      received = receiveTimeout(dur!("msecs")( 100 ), (string message) { 
         writeln("received: ", message); 
      });

      if (!received) { 
         writeln("... no message yet"); 
      }
   } 
}

Yukarıdaki kod derlendiğinde ve çalıştırıldığında, önceki bölümde oluşturulan dosyayı okur ve aşağıdaki sonucu verir -

Waiting for a message 
... no message yet 
... no message yet 
... no message yet 
... no message yet 
received: hello