รับ ID เธรดจากเธรด


319

ใน C # เมื่อทำการดีบักเธรดคุณสามารถดู ID ของแต่ละเธรดได้

ฉันไม่พบวิธีรับเธรดเดียวกันโดยทางโปรแกรม ฉันไม่สามารถรับ ID ของเธรดปัจจุบันได้ (ในคุณสมบัติของThread.currentThread)

ดังนั้นฉันจึงสงสัยว่า Visual Studio รับ ID ของเธรดได้อย่างไรและมีวิธีรับหมายเลขอ้างอิงของเธรดที่มี id 2345อย่างไร

คำตอบ:


437

GetThreadIdส่งคืน ID ของเธรดดั้งเดิมที่กำหนด มีวิธีที่จะทำให้มันทำงานกับเธรดที่ได้รับการจัดการได้ฉันแน่ใจว่าสิ่งที่คุณต้องค้นหาคือตัวจัดการเธรดและส่งผ่านไปยังฟังก์ชันนั้น

GetCurrentThreadId ส่งคืน ID ของเธรดปัจจุบัน

GetCurrentThreadIdเลิกใช้แล้วตั้งแต่. NET 2.0: วิธีที่แนะนำคือThread.CurrentThread.ManagedThreadIdคุณสมบัติ


87
ตั้งแต่ฉันพบสิ่งนี้พิมพ์มันแล้วบอกว่ามันเลิกใช้วิธีปัจจุบันในการทำเช่นนี้คือ Thread.CurrentThread.ManagedThreadId
James

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

15
มีคำแนะนำที่ไม่ดีอยู่ในบทความนี้ มีบางคนแนะนำให้ใช้ "ManagedThreadId" เพื่อระบุเธรด ฉันแก้ไขโพสต์เพื่อลบคำแนะนำ - สิ่งที่มีน้อยมากที่ชี้ให้เห็นคือมี id ของเธรดประเภทต่างๆ ID เธรดที่ได้รับการจัดการไม่เหมือนกับ ID ของเธรดที่ไม่มีการจัดการและหากผู้คนต้องคัดลอกและวางรหัสนั้นอาจมีข้อผิดพลาดในการซิงโครไนซ์ที่ละเอียดอ่อนมาก เอกสารใน MSDN สำหรับคลาสเธรดนั้นชัดเจนมากเกี่ยวกับเรื่องนี้ ดูคำพูดในระดับชั้นเรียน
ShadowChaser

3
คุณไม่ได้ซิงโครไนซ์กับ ID คุณใช้การซิงโครไนซ์ดั้งเดิมเช่น mutexes นี่เป็นเพียงจุดประสงค์ในการตรวจแก้จุดบกพร่อง
Blindy

11
ผมอยากจะแสดงความคิดเห็นนี้เพื่อแจ้งให้ทราบว่าจะไม่ทำงานอย่างน้อยเมื่อใช้ในSystem.Threading.Thread.CurrentThread.ManagedThreadId SetWindowsHookExแต่เราจะต้องได้รับด้าย id GetCurrentThreadId()จากฟังก์ชั่น
King King

82

ใน C # เมื่อทำการดีบักเธรดคุณสามารถดู ID ของแต่ละเธรดได้

นี่จะเป็นรหัสของเธรดที่ได้รับการจัดการ ManagedThreadIdเป็นสมาชิกThreadเพื่อให้คุณสามารถรับรหัสจากวัตถุใด ๆเธรด สิ่งนี้จะทำให้คุณได้รับManagedThreadIDปัจจุบัน:

Thread.CurrentThread.ManagedThreadId

เพื่อรับเธรด OS โดยเป็น ID เธรด OS (ไม่ใช่ ManagedThreadID)คุณสามารถลองใช้ linq ได้บ้าง

int unmanagedId = 2345;
ProcessThread myThread = (from ProcessThread entry in Process.GetCurrentProcess().Threads
   where entry.Id == unmanagedId 
   select entry).First();

ดูเหมือนว่าไม่มีวิธีที่จะระบุเธรดที่ได้รับการจัดการและไม่มีความสัมพันธ์ระหว่าง ProcessThread และเธรดดังนั้นการรับเธรดที่มีการจัดการโดย Id จึงเป็นสิ่งที่ยาก

สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับเธรดที่ได้รับการจัดการเทียบกับไม่ได้รับการจัดการโปรดดูที่บทความ MSDNนี้


4
ทำไมไม่มีใครมาด้วยคำตอบง่ายๆนี้
Stefan Steinegger

2
สิ่งนี้ใช้ไม่ได้ GetCurrentProcess () เธรดส่งคืน ProcessThreadCollection ซึ่งไม่สามารถแปลงเป็นเธรดได้ ฉันไม่เห็นวิธีแก้ไขที่ง่าย
mafu

2
@ mafutrct คำตอบที่อัพเดต ควรเรียกคุณสมบัตินั้นว่า .ProcessThreads! ขอบคุณ
badbod99

2
แนะนำโพสต์นี้ถูกเขียนใหม่เพื่อให้ชัดเจนยิ่งขึ้นว่ารหัสด้ายทั้งสองนั้นแตกต่างกัน หากใครบางคนไม่สามารถอ่านประโยคสุดท้ายพวกเขาก็จะเสียบ ManagedThreadId และพยายามแมปมันกับ ProcessThread.Id สร้าง havok
ShadowChaser

1
ฉันได้เพิ่มลิงก์ไปยัง acticle MSDN ที่มีประโยชน์ซึ่งเน้นความแตกต่าง อย่างไรก็ตามคำถามเกี่ยวข้องกับการรับ ID ของเธรดสำหรับการดีบัก (ซึ่งในกรณีนี้คือ ManagedThreadID) ฉันไม่คิดว่าคำตอบที่ยุ่งเหยิงโดยมีรายละเอียดของความแตกต่างระหว่าง OS และเธรดที่มีการจัดการมีประโยชน์
badbod99

46

คุณสามารถใช้เลิกใช้AppDomain.GetCurrentThreadIdเพื่อรับ ID ของเธรดที่กำลังรันอยู่ วิธีนี้ใช้ PInvoke กับวิธี Win32 API GetCurrentThreadIDและจะส่งคืน ID เธรด Windows

วิธีนี้ถูกทำเครื่องหมายว่าเลิกใช้แล้วเนื่องจากวัตถุ. NET Thread ไม่สอดคล้องกับเธรด Windows เดี่ยวและดังนั้นจึงไม่มี ID ที่เสถียรซึ่ง Windows สามารถส่งคืนได้สำหรับเธรด. NET ที่ระบุ

ดูคำตอบของตัวกำหนดค่าด้วยเหตุผลเพิ่มเติมว่าทำไมในกรณีนี้


ข้อควรระวังกับสุทธิหลัก 2.2 ทราบว่า AppDomain.GetCurrentThreadId (ผมเรียกผ่าน MethodInfo เป็นเลิก) ผลตอบแทน ID ที่หัวข้อการจัดการ (ไร้ประโยชน์สำหรับการจับคู่ Process.GetCurrentProcess () คอลเลกชันด้าย..
brewmanz

32

ในการรับ OS ID ให้ใช้:

AppDomain.GetCurrentThreadId()

1
GetHashCode ไม่จำเป็นต้องซ้ำกัน! และไม่ควรใช้เพื่อระบุเธรด
Dror Helper

2
คุณสามารถใช้ AppDomain.GetCurrentThreadId () ถ้าคุณต้องการ ID เธรด OS แต่หลาย ๆ เธรด. NET สามารถทำได้ในทางทฤษฎีโดยใช้เธรด OS เดียวกันร่วมกัน Thread.GetHashCode () รับประกันว่าจะส่งคืนค่าที่เป็นกระบวนการที่ไม่ซ้ำกันซึ่งเป็นสิ่งที่คุณอาจต้องการ
Mark Byers

3
วิธีการถูกทำเครื่องหมายว่าเลิกใช้แล้วและมีเหตุผลที่ดี โปรดดูคำตอบและตัวกำหนดค่าของฉันสำหรับภาพเต็ม
Paul Turner

3
นี่เป็นวิธีเดียวที่จะได้รับ ID เธรด OS และควรทำเครื่องหมายเป็นคำตอบที่ถูกต้อง แม้ว่าฉันจะไม่เชื่อเรื่องนี้อีกแล้ว
LolaRun

1
AppDomain.GetCurrentThreadId()เป็นล้าสมัย: ได้เลิกเพราะมันไม่ได้ให้รหัสที่มีเสถียรภาพเมื่อหัวข้อการจัดการกำลังทำงานอยู่บนAppDomain.GetCurrentThreadId fibers (aka lightweight threads)ที่จะได้รับรหัสคงที่สำหรับหัวข้อการจัดการใช้ทรัพย์สินในManagedThreadId Threadการใช้งาน:Thread.CurrentThread.ManagedThreadId
Lijo Joseph

22

อ้างอิงจากMSDN :

ThreadId ระบบปฏิบัติการไม่มีความสัมพันธ์คงที่กับเธรดที่ได้รับการจัดการเนื่องจากโฮสต์ที่ไม่มีการจัดการสามารถควบคุมความสัมพันธ์ระหว่างเธรดที่ได้รับการจัดการและที่ไม่มีการจัดการได้ โฮสต์ที่มีความซับซ้อนสามารถใช้ CLR Hosting API เพื่อกำหนดเวลาเธรดที่มีการจัดการจำนวนมากกับเธรดระบบปฏิบัติการเดียวกันหรือเพื่อย้ายเธรดที่มีการจัดการระหว่างเธรดระบบปฏิบัติการที่แตกต่างกัน

ดังนั้นโดยทั่วไปThreadวัตถุไม่จำเป็นต้องสอดคล้องกับเธรด OS - ซึ่งเป็นสาเหตุที่ไม่มี ID ดั้งเดิมที่เปิดเผย


หน้าต่าง Debug / Threads ใน VS2010 แสดง "Managed thread ID" ฉันจะรับอันนี้ได้อย่างไร
Pavel Radzivilovsky

1
ใช้คุณสมบัติManagedThreadID msdn.microsoft.com/en-us/library/… . สิ่งนี้ไม่เหมือนกับ ID เธรดของระบบปฏิบัติการ
กำหนดค่า

15

สำหรับผู้ที่กำลังจะแฮ็ค:

    public static int GetNativeThreadId(Thread thread)
    {
        var f = typeof(Thread).GetField("DONT_USE_InternalThread",
            BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);

        var pInternalThread = (IntPtr)f.GetValue(thread);
        var nativeId = Marshal.ReadInt32(pInternalThread, (IntPtr.Size == 8) ? 548 : 348); // found by analyzing the memory
        return nativeId;
    }

11

ในการค้นหา Id ของเธรดปัจจุบันให้ใช้ - `Thread.CurrentThread.ManagedThreadId ' แต่ในกรณีนี้คุณอาจต้องใช้ win32 thread id ปัจจุบัน - ใช้ pInvoke เพื่อรับมันด้วยฟังก์ชั่นนี้:

[DllImport("Kernel32", EntryPoint = "GetCurrentThreadId", ExactSpelling = true)]
public static extern Int32 GetCurrentWin32ThreadId();

ก่อนอื่นคุณจะต้องบันทึก thread id ที่มีการจัดการและการเชื่อมต่อ win32 thread id - ใช้พจนานุกรมที่แมป win32 id กับ thread ที่มีการจัดการ

จากนั้นหาเธรดโดยใช้ id วนซ้ำไปตามเธรดของกระบวนการโดยใช้ Process.GetCurrentProcess () เธรดและค้นหาเธรดที่มี id นั้น:

foreach (ProcessThread thread in Process.GetCurrentProcess().Threads)
{
     var managedThread = win32ToManagedThread[thread.id];
     if((managedThread.ManagedThreadId == threadId)
     {
         return managedThread;
     }
}

ฉันเชื่อว่า OP ขอรหัส OS ของเธรดซึ่งไม่เหมือนกับ ID เธรดที่ได้รับการจัดการ
Brian Rasmussen

รหัสนี้ใช้งานไม่ได้: กระบวนการเธรดส่งคืนคอลเลกชันของProcessThreadวัตถุซึ่งไม่เหมือนกับ (หรือไม่สืบทอด) Thread: (thread as Thread)จะส่งคืนการอ้างอิงแบบ null
Fredrik Mörk

ฉันพบว่ารหัสที่มีข้อบกพร่องบาง - คงได้ลองตอนนี้
Dror Helper

1
ฉันลงเอยด้วยการใช้พจนานุกรมที่จับคู่รหัส win32 กับเธรดที่ได้รับการจัดการ
Contango

11

ออฟเซ็ตภายใต้ Windows 10 คือ 0x022C (x64-bit-Application) และ 0x0160 (x32-bit-Application):

public static int GetNativeThreadId(Thread thread)
{
    var f = typeof(Thread).GetField("DONT_USE_InternalThread",
        BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);

    var pInternalThread = (IntPtr)f.GetValue(thread);
    var nativeId = Marshal.ReadInt32(pInternalThread, (IntPtr.Size == 8) ? 0x022C : 0x0160); // found by analyzing the memory
    return nativeId;
}

1
ทำงานบน Windows 7 x64 พร้อม SP1 เช่นกัน ไม่แนะนำแม้ว่า ใช้ในการทดสอบชั่วคราวเท่านั้น
guan boshen


5

จากรหัสที่ได้รับการจัดการคุณสามารถเข้าถึงอินสแตนซ์ของThreadประเภทสำหรับแต่ละเธรดที่ได้รับการจัดการ Threadห่อหุ้มแนวคิดของเธรด OS และ CLR ปัจจุบันมีความสอดคล้องแบบหนึ่งต่อหนึ่งกับเธรดที่ได้รับการจัดการและเธรด OS อย่างไรก็ตามนี่เป็นรายละเอียดการนำไปปฏิบัติซึ่งอาจมีการเปลี่ยนแปลงในอนาคต

ID ที่แสดงโดย Visual Studio เป็น ID เธรด OS จริง ๆ สิ่งนี้ไม่เหมือนกับ ID เธรดที่ได้รับการจัดการตามคำแนะนำจากหลายคำตอบ

Threadประเภทไม่รวมถึงสนามสมาชิก IntPtr ส่วนตัวที่เรียกว่าDONT_USE_InternalThreadซึ่งชี้ไปที่โครงสร้างพื้นฐานของระบบปฏิบัติการ อย่างไรก็ตามเนื่องจากนี่เป็นรายละเอียดการใช้งานจริงจึงไม่แนะนำให้ทำตาม IMO นี้ และเรียงลำดับชื่อบ่งชี้ว่าคุณไม่ควรเชื่อถือสิ่งนี้


ในการใช้ GetThreadId คุณจะต้องใช้จุดจับ - ซึ่งคุณได้รับจากช่อง DONT_USE
ปรับแต่งค่า

ฉันรู้ แต่อย่างที่ฉันบอกว่าคุณไม่สามารถนับจำนวนจริงได้ที่การจัดการเธรดแมปโดยตรงกับเธรด OS ดังนั้นฉันจะไม่นับ
Brian Rasmussen

ขอบคุณมากสำหรับการชี้แจงและสรุปปัญหา แต่ตอนนี้ถ้าเธรดที่ได้รับการจัดการหลายรายการสามารถสอดคล้องกับเธรด OS เดี่ยว (ตามที่ระบุไว้ - และเขาขอบคุณ) นั่นหมายความว่า VS กำลังแสดงเธรด OS และไม่ใช่เธรดที่ได้รับการจัดการ
LolaRun

@OhrmaZd: ใช่ VS2005 / 2008 แสดง ID ระบบปฏิบัติการสำหรับเธรดที่ได้รับการจัดการในหน้าต่างเธรด VS2010B2 แสดงทั้งระบบปฏิบัติการและ ID ที่ถูกจัดการต่อเธรดจริง ๆ
Brian Rasmussen

@Brian Rasmussen: ตอนนี้มันเป็นตัวตนของเธรดที่ได้รับการจัดการ! ขอบคุณสำหรับการแบ่งปันความรู้ของคุณ
LolaRun

4

คุณสามารถใช้ Thread.GetHashCode ซึ่งส่งคืน ID เธรดที่ได้รับการจัดการ ถ้าคุณคิดเกี่ยวกับวัตถุประสงค์ของ GetHashCode สิ่งนี้สมเหตุสมผลดี - มันต้องเป็นตัวบ่งชี้เฉพาะ (เช่นคีย์ในพจนานุกรม) สำหรับวัตถุ (เธรด)

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

GetHashCode "ให้รหัสแฮชนี้สำหรับอัลกอริทึมที่ต้องการตรวจสอบความเท่าเทียมกันของวัตถุอย่างรวดเร็ว" ดังนั้นจึงเหมาะสำหรับการตรวจสอบความเท่าเทียมกันของเธรด - ตัวอย่างเช่นเพื่อยืนยันว่ามีวิธีการใดดำเนินการกับเธรดที่คุณต้องการเรียกใช้


4
ยอดเยี่ยมฉันเพิ่งเปิดคำถามอายุ 5 ปีนี้หนึ่งชั่วโมงกลับมาแล้วเห็น "1 คำตอบใหม่สำหรับคำถามนี้": D
Ray

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

ดีฉันอยู่ในเขตข้อมูลที่แตกต่างกันในตอนนี้ แต่หลังจากนั้นเรามีสอง ID สำหรับเธรด id ของเธรดดั้งเดิมและรหัสสำหรับเธรดที่ได้รับการจัดการและอีกรายการหนึ่งเป็นของอีกรายการหนึ่ง ... โดยหลักแล้ว รหัสมีวัตถุประสงค์เพื่อระบุเธรด GetHashCodes มีโปรแกรมอรรถประโยชน์อื่น ๆ และอาจชนกัน นักพัฒนากรอบการทำงานจะไม่ใช้ ID หากเราต้องใช้ GetHashCode
LolaRun

3
@yoyo Collisions ไม่ทำลายการใช้พจนานุกรม พวกเขาถูกออกแบบมาให้มีความน่าจะเป็นของการชนต่ำไม่ใช่การชนเลย หากคุณแฮชค่า 128 บิตเป็นค่า 64 บิตค่าแฮชทั้งหมดจะมีการชนกันประมาณ2 ^ 64 พจนานุกรมได้รับการออกแบบให้มีอัลกอริทึมทางเลือกเมื่อเกิดการชนในกรณีที่หายาก
bradgonesurfing

2
@ bradgonesurfing คุณพูดถูกและความคิดเห็นก่อนหน้าของฉันผิด ประสิทธิภาพของพจนานุกรมจะลดลงเมื่อมีการแฮช แต่การทำงานยังคงถูกต้อง ฉันขอโทษสำหรับความคิดเห็นที่ทำให้เข้าใจผิดขอบคุณที่ชี้ให้เห็นว่า
yoyo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.