วิธีการดีบักเธรดเดียวใน Visual Studio ได้อย่างไร


254

ฉันมีทางออกสำหรับบางโครงการ มีหลายจุดแตกต่างในโครงการที่แตกต่างกัน ฉันต้องการติดตามเธรดแรกที่ตีหนึ่งในจุดหยุดพักเหล่านี้และทำการติดตามเธรดเดี่ยวนั้นต่อไปแม้ว่าจะมีเธรดอื่น ๆ ที่ป้อนบล็อกโค้ดเดียวกัน

ฉันรู้ว่าสิ่งนี้เป็นไปได้ด้วยการกำหนดเงื่อนไขในจุดพักนั่นคือ thread name = ... หรือ thread Id = ... แต่กรณีของฉันเป็นแอปพลิเคชันASP.NET ที่โหลดหนักและทันทีที่ฉันเชื่อมต่อกับw3wp.exeหลาย ๆ กระทู้จะตีจุดพัก ThreadLocal<break-point>ฉันต้องการบางสิ่งบางอย่างเช่น

เป็นไปได้ไหม? ถ้าเป็นเช่นนั้นได้อย่างไร


7
@ เปาโล: เว็บแอปพลิเคชั่นนี้ทำงานเป็นหัวใจของเว็บฟาร์มขนาดใหญ่และสถานการณ์รถบั๊กกี้นั้นเป็นไปไม่ได้ที่จะเลียนแบบในการทดสอบสถานการณ์
Xaqron

สำหรับ VS 2019 บางทีคุณควรลองสิ่งนี้: stackoverflow.com/a/61868591/8579563
Gozo

คำตอบ:


150

เธรด Freeze / Thaw เป็นวิธีที่ไม่ถูกต้องเนื่องจากเธรดอื่นไม่ได้รันโค้ดใด ๆ

วิธีที่ถูกต้องและใช้งานได้มากที่สุดคือ:

  1. กด Ctrl + A ในหน้าต่างเบรกพอยต์ (เลือกเบรกพอยต์ทั้งหมด)
  2. คลิกขวาและเลือก "ตัวกรอง ... "
  3. ป้อน "ThreadId = (id เธรดปัจจุบัน)"

ในVisual Studio 2015และใหม่กว่ากระบวนการจะคล้ายกัน:

  1. กด Ctrl + A ในหน้าต่างเบรกพอยต์ (เลือกเบรกพอยต์ทั้งหมด)
  2. คลิกขวาและเลือก "การตั้งค่า ... "
  3. ตรวจสอบ "เงื่อนไข" และเลือก "ตัวกรอง" ในเมนูแบบเลื่อนลง
  4. ป้อน "ThreadId = (id เธรดปัจจุบัน)"

ดังนั้นเธรดทั้งหมดจะถูกดำเนินการ แต่ตัวดีบักจะไปที่เธรดปัจจุบันเท่านั้น


51
สิ่งนี้ป้องกันไม่ให้คำสั่งดีบักเกอร์ "ขั้นตอน" เข้าสู่เธรดอื่นหรือไม่ นั่นเป็นปัญหาใหญ่ที่ฉันมี ฉันก้าวผ่านเธรดของฉันและจู่ๆฉันก็อยู่ในส่วนของโค้ดที่ไม่เกี่ยวข้องทั้งหมด ฉันไม่ได้พัฒนาใน Visual Studio อีกต่อไปดังนั้นฉันจึงไม่สามารถทดสอบได้
Matt Faus

8
คลิกขวาในหน้าต่างเบรกพอยต์ไม่มีคำสั่ง "ตัวกรอง" ... และคุณจะค้นหา ID เธรดปัจจุบันได้อย่างไร - คุณจะไปที่หน้าต่างทันทีและพิมพ์System.Threading.Thread.CurrentThread.ManagedThreadIdหรืออะไรสักอย่าง?
BrainSlugs83

5
ใน VS ของฉัน (2015, Community Edition) ฉันไม่สามารถแก้ไขการตั้งค่าของเบรกพอยต์หลายจุดพร้อมกันได้ ดังนั้นตัวกรองสามารถตั้งค่าได้ทีละตัว
robert4

5
ฉันมีปัญหานี้ตลอดไปและฉันสามารถสาบานได้ว่างานล่าสุดของฉันฉันพบการตั้งค่าที่ทำให้สตูดิโอภาพทำงานเช่นคราสที่คุณติดกับเธรดที่คุณทำงานด้วย แต่ฉันไม่พบมันหรืออ้างอิงใด ๆ เพื่อมัน ฉันเริ่มสงสัยว่าฉันฝันมัน
STU

7
-1 เนื่องจากสิ่งนี้อนุญาตให้ใช้กับจุดพักเท่านั้น แต่ไม่สามารถดีบักได้จริง: การก้าวข้าม / ก้าวเข้าสู่ไม่ได้ใช้วิธีนี้ในการดีบักเธรดเดี่ยว
Serge Rogatch

338

นี่คือสิ่งที่ฉันทำ:

  1. กำหนดจุดพักแบบมีเงื่อนไขที่ฉันรู้ว่าจะไปกดบนเธรดที่ฉันค้นหาเท่านั้น

  2. เมื่อเบรกพอยต์ฮิตและคุณอยู่ในเธรดที่คุณต้องการในหน้าต่าง Visual Studio Threads (ในขณะที่การดีบัก Debug -> Windows -> Threads), Ctrl+ A(เพื่อเลือกเธรดทั้งหมด) จากนั้นCtrlคลิก + เธรดที่คุณกำลังใช้อยู่ . คุณควรมีเธรดทั้งหมดยกเว้นที่คุณต้องการตรวจแก้จุดบกพร่องที่เลือก

  3. คลิกขวาและเลือก "หยุด"

ตอนนี้ Visual Studio จะดำเนินการตามเธรดที่ถูกละลายเท่านั้น ดูเหมือนว่าจะช้ากว่านี้มากเมื่อทำสิ่งนี้น่าจะเป็นเพราะมันต้องวนซ้ำไปตามเธรดที่ตรึงไว้ทั้งหมด แต่มันทำให้บางคนมีสติในการดีบั๊กแบบมัลติเธรดของฉัน


1
สิ่งนี้ไม่ทำงานสำหรับฉันในบริบทที่ฉันมีงานประมาณ 8 งานที่ทำงานในเธรดที่แตกต่างกัน ฉันตรึงเธรดอื่นทั้งหมดและ "ก้าวข้าม" แต่ IDE ค้างไว้ครู่หนึ่งแล้วก็ข้ามไปยังเธรดอื่นต่อไป
Meta-Knight

3
@Diego: ฉันไม่ได้ทำงานในโครงการอีกต่อไป แต่ถ้ามันจะหยุดกระทู้ทั้งหมดยกเว้นหนึ่งมันจะเปลี่ยนสถานการณ์ที่ก่อให้เกิดข้อผิดพลาดเนื่องจากกระทู้ที่เสริมในสถานการณ์รถ แม้ว่านี่จะเป็นโซลูชันที่สง่างาม แต่ดูเหมือนว่าคุณสมบัตินี้ควรจะฝังลงใน VS
Xaqron

3
@ Meta-Knight คุณควรตรึงเธรดทั้งหมดยกเว้นเธรดหลัก ถ้าคุณจะทำเช่นนี้ IDE จะไม่ถูกแช่แข็ง
อเล็กซ์ Zhukovskiy

15

ฉันเพิ่งเปิดตัวส่วนขยาย Visual Studio 2010+ ที่ทำสิ่งที่คุณต้องการอย่างแท้จริง และได้ฟรี :)

การเสนอ

ส่วนขยายของ Visual Studio นี้เพิ่มทางลัดและปุ่มแถบเครื่องมือสองปุ่มเพื่อให้นักพัฒนาสามารถโฟกัสที่เธรดเดี่ยวได้อย่างง่ายดายในขณะที่การดีบักแอปพลิเคชันแบบมัลติเธรด

มันลดความจำเป็นในการเข้าไปในหน้าต่างเธรดด้วยตนเองอย่างมากเพื่อตรึง / ละลายเธรดทั้งหมด แต่เธรดที่ต้องติดตามและช่วยปรับปรุงประสิทธิภาพการทำงาน

คุณสมบัติ

จำกัด การดำเนินการเพิ่มเติมให้กับเธรดปัจจุบันเท่านั้น จะตรึงเธรดอื่นทั้งหมด ทางลัด: ปุ่ม CTRL + T + T หรือสโนว์เฟลก สลับไปยังเธรดเดี่ยวถัดไป (อิงตาม ID) จะเปลี่ยนเธรดปัจจุบันและตรึงเธรดอื่นทั้งหมด ทางลัด: CTRL + T + J หรือปุ่มถัดไป

ตรวจสอบออกที่นี่ในแกลเลอรี่บนเว็บอย่างเป็นทางการหรือพื้นที่เก็บข้อมูล Github


คุณใช้ VS เวอร์ชันใด
Erwin Mayer

ฉันติดตั้งส่วนขยายแล้ว แต่ไม่สามารถจัดการให้ใช้งานได้ (สำหรับโครงการปัจจุบันของฉันฉันใช้ VS2010) [โดยวิธีที่ฉันคิดว่าเป็นปัญหากับเธรดที่ใช้งานอยู่เพิ่งเกิดขึ้นเมื่อเธรดถูกสร้างขึ้นมันอาจเป็นพฤติกรรมมาตรฐานดังนั้นฉันจึงลบความคิดเห็นก่อนหน้านี้ออก]
เช็ด

3
ฉันจะตรวจสอบเรื่องนี้ คุณอาจเป็นคนเดียวในโลกที่พยายามแก้ไขข้อบกพร่องที่ใหญ่ที่สุดของไมโครซอฟท์
stu

อนิจจามันจะไม่ติดตั้งใน vs2012 คุณมีเวอร์ชันที่ใหม่กว่าหรือคุณต้องการแบ่งปันซอร์สโค้ดเพื่อให้ฉันสามารถสร้างมันขึ้นมาเองได้หรือไม่?
stu

@stu ซอร์สโค้ดอยู่บน Codeplex ที่นี่: singlethread.codeplex.comควรทำงานกับ VS 2012 และ VS 2013 แต่ฉันยังไม่ได้อัปเดต (ไม่มีใครขอมัน หากคุณสามารถทำให้มันใช้งานได้ง่ายกับ VS 2012+ และทำการคอมมิชชันบน Codeplex ฉันก็สามารถดันมันเข้าไปในแกลเลอรี่ได้เช่นกัน
เออร์วินเมเยอร์

13

หากมีเธรดหลายตัวกำลังถูกวางไข่สำหรับเว็บแอปพลิเคชันคำตอบ @MattFaus จะไม่ทำงาน สิ่งที่ฉันทำแทนคือต่อไปนี้

  • ตั้งค่าเบรกพอยต์เพื่อขัดจังหวะเธรดในฟังก์ชันที่ฉันต้องการ
  • เมื่อเธรดมาถึงเบรกพอยต์และหยุดชั่วคราวฉันจะลบเบรกพอยต์และทำการดีบักต่อโดยใช้ F8, F10 และ F11 เพื่อให้เธรดอื่นสามารถรันได้

หลังจากอ่าน anserws ทั้งหมดแล้ววิธีแก้ปัญหานี้ใช้ได้สำหรับฉัน
Swanand Pangam

9

เล็กน้อยวิธีการที่แตกต่างกันซึ่งผมเคยใช้:

  1. สร้างเบรกพอยต์ปกติและปล่อยให้มันโดน
  2. ค้นหาในหน้าต่างเธรดของคุณเพื่อหา ID เธรดที่ได้รับการจัดการซึ่งคุณกำลังทำการดีบัก
  3. คลิกขวาที่เบรกพอยต์ของคุณในหน้าต่างเบรกพอยต์และเลือกตัวกรอง
  4. ป้อน ThreadId = xxx โดยที่ xxx คือ ID เธรดจาก 2
  5. ตอนนี้คุณสามารถดีบักโดยไม่หยุดเธรดอื่น ๆ และไม่ให้พวกเขากดจุดพักของคุณ

สิ่งนี้จะถือว่าคุณมีเวลาที่จะทำข้างต้นก่อนที่หัวข้อที่สองจะถึงจุดพัก หากไม่มีและเธรดอื่น ๆ กดเบรกพอยต์ของคุณก่อนที่คุณจะทำข้างต้นคุณสามารถคลิกขวาได้ในหน้าต่างกระทู้และเลือกตรึง


3
+1 "นี่จะถือว่าคุณมีเวลา ... ก่อนที่เธรดที่สองจะมาถึงจุดพักของคุณ" ฉันใส่เครื่องหมายอัฒภาคในล็อกแล้ววางเบรกพอยต์บนเครื่องหมายอัฒภาค เมื่อเบรกพอยต์ถูกกดครั้งแรกฉันจะปิดการใช้งานเบรกพอยต์ ไม่มีเธรดอื่น ๆ เข้ามาได้เนื่องจากล็อค lock(m_someObject) { ; }
bluedog

หากต้องการบันทึก Google ให้คุณพบหน้าต่างเธรดภายใต้ดีบั๊ก> Windows> เธรด
Gabe

2

ใน VS 2019:

  1. ตั้งจุดพักที่ไหนสักแห่ง
  2. กด F5 (ดำเนินการต่อ) จนกว่าเธรดของคุณจะมาถึง
  3. คลิกที่เบรกพอยต์เพื่อลบ
  4. คุณสามารถก้าวด้ายด้วย F10 หรือ F11

ทำงานสำหรับ VS2015 ด้วย!
ยุคก่อนประวัติศาสตร์

1

ฉันขอแนะนำให้เพิ่มอินสแตนซ์อื่นของแอปพลิเคชันบนเซิร์ฟเวอร์สดไม่ว่าจะบนฮาร์ดแวร์เดียวกันหรือเครื่องใหม่ (ทำคลัสเตอร์) จากนั้นทำการดีบักอินสแตนซ์นั้นเท่านั้น ฉันจะไม่เพิ่มเบรกพอยต์ในรหัสที่ผู้ใช้กำลังเรียก หากไม่ใช่ตัวเลือกฉันจะเพิ่มการติดตามเพิ่มเติม

อย่างไรก็ตามหากจำเป็นและคุณต้องการสถิติโซลูชันฉันแน่ใจว่าคุณสามารถเพิ่มเบรกพอยต์ที่หยุดพักหากคำขอมาจากที่อยู่ IP ของคุณ คุณจะทำเช่นนี้โดยการเพิ่มจุดพักตามเงื่อนไขที่ HttpContext.Request.UserHostAddressInspects อย่างไรก็ตามโปรดทราบว่านี่จะทำให้ใบสมัครของคุณช้าลงอย่างมาก


นั่นคือสิ่งที่ฉันได้ลอง ปัญหาคืออินสแตนซ์นี้ไม่ทำงานบนโดเมนเดียวกัน (ทำงานบน IP หรือโดเมนอื่น) และสิ่งนี้นำไปสู่ปัญหาใบรับรองจำนวนมาก (SSL, WCF, ... ) และภายใต้สถานการณ์โหลดต่ำรถบั๊กกี้ไม่เคยเกิดขึ้น!
Xaqron

ขออภัยฉันไม่แน่ใจว่าสิ่งเหล่านี้ที่คุณได้ลองคุณได้ลองเบรกพอยต์แบบมีเงื่อนไขหรือไม่?
steinar

ใช่ฉันตั้งชื่อพวกเขาตามรหัสที่จัดการของพวกเขาเพื่อให้แน่ใจว่าไม่ซ้ำกัน จากนั้นก็ยากที่จะคาดเดาว่า Id ใดที่ได้รับมอบหมายและตั้งเงื่อนไขตามการเดา บางครั้งการเดาใกล้และบางครั้งมันใช้เวลานานในการจับเธรด
Xaqron

1

ถ้าคุณไม่ต้องการหยุดเธรดอื่น ๆ ทั้งหมด (บางทีคุณกำลังแนบดีบักเกอร์ Visual Studio กับแอปพลิเคชันที่ทำงานซึ่งจำเป็นต้องตอบคำขอ) คุณสามารถใช้แมโครที่สร้างและลบเบรกพอยต์โดยอัตโนมัติ

นี้เป็นข้อเสนอแนะในการตอบคำถามกองมากเกิน"ขั้นตอนมากกว่า" เมื่อการดีบักโปรแกรมแบบมัลติเธรดใน Visual Studio

อย่างไรก็ตามลิงก์จะอธิบายเฉพาะวิธีการดีบักทีละบรรทัด ฉันขอแนะนำให้คุณแก้ไขแมโคร (หากคุณพอใจ) เพื่อให้แก้ไขจุดพักทั้งหมด (ในช่วงของบรรทัดที่ระบุ) เพื่อหยุดเฉพาะในเธรดปัจจุบัน


1

ฉันคิดว่านี่เป็นสิ่งที่แตกต่างกันเล็กน้อยใน Visual Studio 2015 พวกเขาเปลี่ยนบางสิ่งในเบรกพอยต์ แต่นี่คือวิธีใช้คำตอบที่ยอมรับจาก hzdbyte (ด้านบน):

บนเบรกพอยต์ในระยะขอบการเข้ารหัสคลิกขวา> เงื่อนไข> เปลี่ยนจาก 'นิพจน์ตามเงื่อนไข' เป็น 'ตัวกรอง' สิ่งนี้จะช่วยให้คุณสามารถกรองตาม ThreadId

อีกทางเลือกหนึ่งในเบรกพอยต์ในหน้าต่างเบรกพอยต์คลิกขวา> การตั้งค่า> ทำเครื่องหมายในช่องเงื่อนไขและทำตามข้างบน


1

ตั้งค่าเงื่อนไขเบรกพอยต์โดยคลิกขวาที่แถบด้านข้างของบรรทัด เลือก "เงื่อนไข" และป้อนชื่อของเธรดของคุณในเครื่องหมายคำพูด:

System.Threading.Thread.CurrentThread.Name == "name_of_your_thread"

หรือคุณสามารถทำได้โดยรับ "Managed ID" จากหน้าต่าง "Threads" และใช้:

System.Threading.Thread.CurrentThread.ManagedThreadId == your_managed_thread_id

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.