การเขียนโปรแกรม D - ภาวะพร้อมกัน
การทำงานพร้อมกันทำให้โปรแกรมทำงานบนเธรดหลายชุดพร้อมกัน ตัวอย่างของโปรแกรมที่ทำงานพร้อมกันคือเว็บเซิร์ฟเวอร์ที่ตอบสนองไคลเอนต์จำนวนมากในเวลาเดียวกัน การเกิดพร้อมกันเป็นเรื่องง่ายเมื่อส่งผ่านข้อความ แต่เขียนได้ยากมากหากใช้ข้อมูลร่วมกัน
ข้อมูลที่ส่งผ่านระหว่างเธรดเรียกว่าข้อความ ข้อความอาจประกอบด้วยประเภทใดก็ได้และตัวแปรจำนวนเท่าใดก็ได้ ทุกเธรดมีรหัสซึ่งใช้สำหรับระบุผู้รับข้อความ เธรดใด ๆ ที่เริ่มเธรดอื่นเรียกว่าเจ้าของกระทู้ใหม่
การเริ่มต้นเธรดใน D
ฟังก์ชัน spawn () ใช้ตัวชี้เป็นพารามิเตอร์และเริ่มเธรดใหม่จากฟังก์ชันนั้น การดำเนินการใด ๆ ที่ดำเนินการโดยฟังก์ชันนั้นรวมถึงฟังก์ชันอื่น ๆ ที่อาจเรียกใช้จะถูกดำเนินการบนเธรดใหม่ เจ้าของและผู้ปฏิบัติงานทั้งสองเริ่มดำเนินการแยกกันราวกับว่าเป็นโปรแกรมอิสระ
ตัวอย่าง
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.");
}
เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานจะอ่านไฟล์ที่สร้างในส่วนก่อนหน้าและสร้างผลลัพธ์ต่อไปนี้ -
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
thisTidตัวแปรทั่วโลกที่มีอยู่ในระดับโมดูลอยู่เสมอ ID ของด้ายปัจจุบัน นอกจากนี้คุณยังสามารถรับ threadId เมื่อเรียก spawn ตัวอย่างแสดงด้านล่าง
ตัวอย่าง
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);
}
เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานจะอ่านไฟล์ที่สร้างในส่วนก่อนหน้าและสร้างผลลัพธ์ต่อไปนี้ -
Owner : Tid(std.concurrency.MessageBox), address: 10C71A59C
Worker: Tid(std.concurrency.MessageBox), address: 10C71A59C
Tid(std.concurrency.MessageBox)
ข้อความผ่านใน D
ฟังก์ชัน send () ส่งข้อความและฟังก์ชัน earnOnly () รอข้อความประเภทใดประเภทหนึ่ง มีฟังก์ชั่นอื่น ๆ ที่ชื่อ prioritySend (), รับ () และรับเวลาเอาท์ () ซึ่งจะอธิบายในภายหลัง
เจ้าของในโปรแกรมต่อไปนี้ส่งข้อความประเภท int ให้ผู้ปฏิบัติงานและรอข้อความจากผู้ปฏิบัติงานประเภท double เธรดยังคงส่งข้อความกลับไปกลับมาจนกว่าเจ้าของจะส่ง int เชิงลบ ตัวอย่างแสดงด้านล่าง
ตัวอย่าง
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);
}
เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานจะอ่านไฟล์ที่สร้างในส่วนก่อนหน้าและสร้างผลลัพธ์ต่อไปนี้ -
sent: 5, received: 25
sent: 6, received: 30
sent: 7, received: 35
sent: 8, received: 40
sent: 9, received: 45
ข้อความผ่านด้วยการรอใน D
ตัวอย่างง่ายๆกับข้อความที่ส่งด้วยการรอแสดงอยู่ด้านล่าง
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");
}
}
}
เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานจะอ่านไฟล์ที่สร้างในส่วนก่อนหน้าและสร้างผลลัพธ์ต่อไปนี้ -
Waiting for a message
... no message yet
... no message yet
... no message yet
... no message yet
received: hello