เธรดปลอดภัยระบบการส่งข้อความแบบอะซิงโครนัสและง่าย ๆ สำหรับการสื่อสารระหว่างคลาส / เลเยอร์ใน Delphi ที่สร้างโดยทีมงาน ipub
Delphi มีระบบการส่งข้อความของตัวเอง (System.Sessaging.PAS) ที่ทำงานได้ดี แต่เป็นแบบซิงโครนัสโดยสิ้นเชิงและไม่ปลอดภัย ในระบบมัลติเธรดเราจำเป็นต้องสื่อสารกับคลาสอื่น ๆ บางครั้งบางครั้งซิงโครนัสบางครั้งแบบอะซิงโครนัสบางครั้งการซิงโครไนซ์กับ mainthread (ในกรณีของ UI) และการทำสิ่งนี้โดยไม่ต้องใช้ระบบข้อความ (สื่อสารโดยตรง) ทำให้รหัสใหญ่และซับซ้อน
ระบบการส่งข้อความในอุดมคติจะเป็นระบบความปลอดภัยของเธรดที่จะอนุญาตให้ชั้นเรียนสมัครสมาชิกแล้วยกเลิกการสมัครรับฟังข้อความเฉพาะในช่วงเวลานี้และคลาสผู้ฟังที่จะได้รับข้อความคือใครจะแจ้งให้ผู้ส่งเรียกวิธีการ ของ มัน: ในเธรดเดียวกัน ( โพสต์ ) บนเธรด หลัก ( หลัก ) นี่คือพื้นฐานของระบบการส่งข้อความของเราการใช้งานคล้ายกับระบบอื่นที่มีอยู่คือ Delphi Event Bus (DEB)
ดูการเปรียบเทียบในสภาพแวดล้อมที่มีวัตถุ 1,000 ชิ้น:
| สมัครสมาชิก | โพสต์ | ยกเลิกการสมัคร | |
|---|---|---|---|
| iPub | 1.6368 ms | 0.1215 ms | 1.7666 ms |
| เดบิวต์ | 9.8832 ms | 2.0293 ms | 4.0022 ms |
ILogOutMessage = interface
[ ' {CA101646-B801-433D-B31A-ADF7F31AC59E} ' ]
// here you can put any data
end ;ก่อนอื่นคุณต้องสมัครรับคลาสของคุณเพื่อฟังข้อความจากนั้นวิธีการสาธารณะทั้งหมดที่มีแอตทริบิวต์ [สมัครสมาชิก] จะถูกสมัคร
TForm1 = class (TForm)
procedure FormCreate (Sender: TObject);
procedure FormDestroy (Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
[Subscribe(TipMessagingThread.Main)]
procedure OnLogout ( const AMessage: ILogOutMessage);
end ;
...
procedure TForm1.FormCreate (Sender: TObject);
begin
GMessaging.Subscribe(Self);
end ;
procedure TForm1.FormDestroy (Sender: TObject);
begin
GMessaging.Unsubscribe(Self);
end ;
procedure TForm1.OnLogout ( const AMessage: ILogOutMessage);
begin
Showmessage( ' Log out! ' );
end ;นอกจากนี้คุณยังสามารถประกาศวิธีการในส่วนที่ได้รับการป้องกัน แต่ในการทำเช่นนี้คุณต้องเพิ่ม {$ rtti วิธีการที่ชัดเจน ([vcprotected, vcpublic, vcpublished])} ก่อนชั้นเรียน
var
LMessage: ILogOutMessage
begin
LMessage := TLogOutMessage.Create;
GMessaging.Post(LMessage);ในตัวอย่างก่อนหน้านี้เราได้แสดงข้อความอินเทอร์เฟซ แต่มีข้อความทั้งหมด 3 ประเภท:
| ตัวตน | พารามิเตอร์ |
|---|---|
| ชื่อ (ชัดเจน) | สาย |
| GUID ของอินเทอร์เฟซพารามิเตอร์ (โดยปริยาย) | ส่วนต่อประสาน |
| GUID ของอินเทอร์เฟซพารามิเตอร์ (โดยปริยาย) + ชื่อ (ชัดเจน) | ส่วนต่อประสาน |
หากต้องการรับข้อความที่มีตัวตนชื่อเพียงประกาศชื่อในแอตทริบิวต์เมธอด:
[Subscribe( ' Name ' , TipMessagingThread.Main)]หากต้องการส่งข้อความที่มีตัวตนชื่อเพียงแจ้งในการโทรโพสต์:
GMessaging.Post( ' Name ' , LMessage);หมายเหตุ: ชื่อที่ชัดเจนคือตัวพิมพ์ใหญ่
ในแอตทริบิวต์ [สมัครสมาชิก] คุณสามารถพิจารณาได้ว่าวิธีการรับข้อความจะถูกดำเนินการอย่างไร:
| ใจดี | คำอธิบาย |
|---|---|
| TipmessagingThread.posting | ค่าเริ่มต้นเมธอดสมาชิกจะถูกเรียกใช้ในเธรดโพสต์เดียวกันที่มีการเรียกโพสต์ |
| TipmessagingThread.main | วิธีการสมาชิกจะถูกเรียกใช้ในเธรดหลัก |
| TipmessagingThread.async | วิธีการสมาชิกจะถูกเรียกใช้แบบอะซิงโครนัสในเธรด anonnymous ใหม่นอกเหนือจากเธรดการโพสต์ |
| TipmessagingThread.background | หากเธรดการโพสต์เป็นเธรดหลักวิธีการสมาชิกจะถูกเรียกใช้แบบอะซิงโครนัสในเธรด anonnymous ใหม่นอกเหนือจากเธรดการโพสต์ หากเธรดการโพสต์ไม่ใช่เธรดหลักวิธีการสมาชิกจะถูกเรียกใช้ร่วมกันในเธรดการโพสต์เดียวกัน |
แม้ว่าการใช้แอตทริบิวต์ [สมัครสมาชิก] เพื่อสมัครสมาชิกวิธีการใช้งานได้จริง แต่ก็มี จำกัด เพราะคุณต้องกำหนดชื่อของข้อความก่อนการรวบรวมในเวลาออกแบบและบางครั้งมันก็มีประโยชน์จริงๆในการกำหนดชื่อของข้อความในรันไทม์ ตัวอย่างข้อความสำหรับผลิตภัณฑ์ที่มีการเปลี่ยนแปลง 'product_105346_Changed' ชื่อของข้อความนั้นฉันสามารถกำหนดได้ในเวลาทำงานเท่านั้นดังนั้นเราจึงเพิ่มตัวเลือกในการสมัคร / ยกเลิกวิธีการฟังข้อความด้วยตนเอง:
GMessaging.SubscribeMethod<string>( ' product_105346_changed ' , Self.OnProductChanged, TipMessagingThread.Posting);
GMessaging.UnsubscribeMethod<string>( ' product_105346_changed ' , Self.OnProductChanged);วิธีการด้วยตนเองทั้งสองนี้เป็นอิสระจากวิธีการสมัครสมาชิก / ยกเลิกการสมัคร คุณสามารถรวมคลาสเดียวกันกับวิธีการสมัครสมาชิกโดยอัตโนมัติโดยใช้แอตทริบิวต์ [สมัครสมาชิก] และการเรียกสมัครสมาชิก / ยกเลิกการสมัครสมาชิกและในเวลาเดียวกันในคลาสนี้มีวิธีการที่คุณเพิ่มด้วยตนเองโดยใช้สมาชิก / unsubscribemethod
ประโยชน์อีกประการหนึ่งของวิธีการลงทะเบียนด้วยตนเองคือพวกเขาไม่ได้ จำกัด วิธีการสาธารณะเท่านั้น (แม้ว่าปัญหานี้สามารถแก้ไขได้โดยใช้คำสั่งวิธีการที่ชัดเจนของ RTTI)
แนวคิดของระบบเป็นเพียงการส่งต่อข้อความประกาศที่มีหรือไม่ข้อมูลดังนั้นโปรดจำไว้ว่าไม่แนะนำให้วางรหัสหรือรหัสขนาดใหญ่ที่มีการหยุด (รอ) ภายในวิธีการที่สมัครรับฟังข้อความเนื่องจากจะส่งผลโดยตรงต่อประสิทธิภาพของระบบแม้ในโหมดอะซิงโครนัส
การพิจารณาอีกประการหนึ่งเป็นเพียงเครื่องเตือนใจถึงวิธีที่ถูกต้องในการใช้ TTASK ของ Delphi อย่าใช้ TTASK เพื่อดำเนินการวิธีการด้วยการหยุด (เหตุการณ์, semaphores, ... ), มันไม่ได้ทำเพื่อสิ่งนั้นเป้าหมายของมันคือการทำงานอย่างต่อเนื่องและง่ายขึ้นหากงานของคุณซับซ้อนกว่าสิ่งที่ถูกต้องคือการใช้ tthread เราเตือนคุณเกี่ยวกับเรื่องนี้เนื่องจากระบบของเราใช้ TTASK ของ Delphi เพื่อเพิ่มประสิทธิภาพส่วนใหญ่ในสภาพแวดล้อมที่ซับซ้อนมากขึ้นนอกเหนือจากการประหยัดทรัพยากรและหากคุณใช้ TTASK อย่างไม่ถูกต้องในรหัสของคุณคุณสามารถทำให้แอปพลิเคชันของคุณหยุดเมื่อส่งข้อความ
การส่งข้อความ iPub ได้รับอนุญาตภายใต้ MIT และไฟล์ใบอนุญาตจะรวมอยู่ในโฟลเดอร์นี้