ฉันเพิ่งแก้ไขข้อบกพร่องโดยใช้สิ่งนี้:
_Thread.SetApartmentState(ApartmentState.STA);
ตอนนี้ฉันอยากจะเข้าใจว่ามันหมายถึงอะไรและทำไมมันถึงได้ผล!
ฉันเพิ่งแก้ไขข้อบกพร่องโดยใช้สิ่งนี้:
_Thread.SetApartmentState(ApartmentState.STA);
ตอนนี้ฉันอยากจะเข้าใจว่ามันหมายถึงอะไรและทำไมมันถึงได้ผล!
คำตอบ:
COM เป็นบิดาที่ยิ่งใหญ่ของ. NET พวกเขามีเป้าหมายที่สูงส่งทีเดียวหนึ่งในสิ่งที่ COM ทำ แต่. NET ข้ามไปโดยสิ้นเชิงคือการรับประกันเธรดสำหรับคลาส คลาส COM สามารถเผยแพร่ข้อกำหนดของเธรดที่มี และโครงสร้างพื้นฐาน COM ทำให้แน่ใจว่าเป็นไปตามข้อกำหนดเหล่านั้น
สิ่งนี้ไม่มีอยู่ใน. NET โดยสิ้นเชิง คุณสามารถใช้ออบเจ็กต์ Queue <> ในหลายเธรดได้ แต่ถ้าคุณล็อกไม่ถูกต้องคุณจะมีข้อบกพร่องที่น่ารังเกียจในโค้ดของคุณซึ่งยากที่จะวินิจฉัย
รายละเอียดที่แน่นอนของเธรด COM มีขนาดใหญ่เกินไปที่จะใส่ในโพสต์ ฉันจะเน้นเฉพาะคำถามของคุณ เธรดที่สร้างอ็อบเจ็กต์ COM ต้องบอก COM ว่าต้องการให้การสนับสนุนประเภทใดแก่คลาส COM ที่มีอ็อพชันเธรดที่ จำกัด คลาสเหล่านี้ส่วนใหญ่รองรับเฉพาะสิ่งที่เรียกว่า Apartment threading เท่านั้นวิธีการเชื่อมต่อของพวกเขาสามารถเรียกได้อย่างปลอดภัยจากเธรดเดียวกับที่สร้างอินสแตนซ์ กล่าวอีกนัยหนึ่งคือพวกเขาประกาศว่า "ฉันไม่สนับสนุนเธรด แต่อย่างใดโปรดดูแลอย่าโทรหาฉันจากเธรดที่ผิดพลาด" แม้ว่ารหัสไคลเอ็นต์จะเรียกจากเธรดอื่นก็ตาม
มีสองประเภทคือ STA (Single Threaded Apartment) และ MTA ระบุไว้ในการเรียก CoInitializeEx () ซึ่งเป็นฟังก์ชันที่ต้องเรียกใช้โดยเธรดใด ๆ ที่ทำอะไรกับ COM CLR ทำการโทรโดยอัตโนมัติทุกครั้งที่เริ่มเธรด สำหรับเธรดเริ่มต้นหลักของโปรแกรมของคุณจะได้รับค่าที่จะส่งผ่านจากแอตทริบิวต์ [STAThread] หรือ [MTAThread] บนเมธอด Main () ของคุณ ค่าเริ่มต้นคือ MTA สำหรับเธรดที่คุณสร้างขึ้นเองจะถูกกำหนดโดยการเรียกใช้ SetApartmentState () ค่าเริ่มต้นคือ MTA เธรด Threadpool เป็น MTA เสมอซึ่งไม่สามารถเปลี่ยนแปลงได้
มีโค้ดมากมายใน Windows ที่ต้องใช้ STA ตัวอย่างเด่นที่คุณใช้เอง ได้แก่ คลิปบอร์ดลาก + วางและกล่องโต้ตอบเชลล์ (เช่น OpenFileDialog) และโค้ดจำนวนมากที่คุณมองไม่เห็นเช่นโปรแกรม UI Automation และขอเกี่ยวเพื่อสังเกตข้อความ รหัสนั้นไม่จำเป็นต้องเป็นเธรดปลอดภัยผู้เขียนจะมีช่วงเวลาที่ยากลำบากในการทำให้ปลอดภัยโดยไม่ทราบว่าจะใช้โปรแกรมใด ดังนั้นเธรด UI ของโปรเจ็กต์ WPF หรือ Windows Forms ต้องเป็น STA เสมอเพื่อรองรับโค้ดดังกล่าวเช่นเดียวกับเธรดใด ๆ ที่สร้างหน้าต่าง
สัญญาที่คุณทำกับ COM ที่กระทู้ของคุณจะ STA แต่ไม่ต้องการให้คุณทำตามสัญญาที่อพาร์ทเม้นเดียวด้าย พวกเขาค่อนข้างแข็งและคุณอาจยุ่งยากในการวินิจฉัยปัญหาเมื่อคุณผิดสัญญา ข้อกำหนดคือคุณจะไม่บล็อกเธรดเป็นระยะเวลาใด ๆ และคุณต้องปั๊มวนข้อความ ข้อกำหนดหลังเป็นไปตามเธรด UI ของ WPF หรือ Winforms แต่คุณจะต้องดูแลด้วยตัวเองหากคุณสร้างเธรด STA ของคุณเอง การวินิจฉัยทั่วไปสำหรับการทำลายสัญญาคือการหยุดชะงัก
มีการสนับสนุนในตัว CLR เล็กน้อยเพื่อรองรับความต้องการเหล่านี้ btw ช่วยให้คุณหมดปัญหา ล็อคคำสั่งและ WaitOne () วิธีปั๊มห่วงข้อความเมื่อบล็อกบนด้าย STA อย่างไรก็ตามสิ่งนี้ดูแลเฉพาะความต้องการที่ไม่เคยบล็อก แต่คุณยังต้องสร้างลูปข้อความของคุณเอง Application.Run () ทั้งใน WPF และ Winforms
ก่อนหน้านี้ฉันได้ให้คำตอบที่มีรายละเอียดเพิ่มเติมเกี่ยวกับความสำคัญของการวนรอบข้อความเพื่อให้ COM มีความสุข คุณจะพบการโพสต์ที่นี่