Mendapatkan ID utas dari utas

319

Di C # saat men-debug thread misalnya, Anda dapat melihat setiap ID utas.

Saya tidak dapat menemukan cara untuk mendapatkan utas yang sama, secara terprogram. Saya bahkan tidak bisa mendapatkan ID dari utas saat ini (di properti dari Thread.currentThread).

Jadi, saya bertanya-tanya bagaimana Visual Studio mendapatkan ID dari utas, dan apakah ada cara untuk mendapatkan pegangan dari utas dengan id 2345, misalnya?

LolaRun
sumber

Jawaban:

437

GetThreadIdmengembalikan ID dari utas asli yang diberikan. Ada cara untuk membuatnya bekerja dengan utas yang dikelola, saya yakin, semua yang Anda perlu temukan adalah pegangan utas dan meneruskannya ke fungsi itu.

GetCurrentThreadId mengembalikan ID dari utas saat ini.

GetCurrentThreadIdtelah ditinggalkan sejak. NET 2.0: cara yang disarankan adalah Thread.CurrentThread.ManagedThreadIdproperti.

Buta
sumber
87
Karena saya menemukan ini, mengetiknya, dan kemudian diberitahu bahwa itu sudah usang, cara saat ini untuk melakukan ini adalah Thread.CurrentThread.ManagedThreadId
James
3
ManagedThreadId bukan pendekatan yang kuat untuk mengidentifikasi utas sebagai id properti ManagedThreadId yang dapat digunakan kembali oleh aplikasi Anda. Jadi itu bukan pengidentifikasi yang dapat diandalkan untuk utas dalam beberapa skenario dan Anda akan mengalami pengecualian: "Item dengan kunci yang sama telah ditambahkan." pada baris ... Berikan utas nama unik saat Anda membuatnya.
Forer
15
Ada beberapa saran buruk yang beredar di pos ini. Beberapa orang merekomendasikan untuk menggunakan "ManagedThreadId" untuk mengidentifikasi utas. Saya mengedit posting untuk menghapus rekomendasi - yang sangat sedikit ditunjukkan adalah bahwa ada berbagai jenis id benang. ID utas yang dikelola tidak sama dengan id utas yang tidak dikelola, dan jika orang ingin menyalin & menempel kode itu, beberapa bug sinkronisasi yang sangat halus dapat terjadi. Dokumentasi tentang MSDN untuk kelas Thread sangat jelas tentang ini. Lihat komentar di tingkat kelas.
ShadowChaser
3
Anda tidak melakukan sinkronisasi pada ID, Anda menggunakan primitif sinkronisasi seperti mutex. Ini hanya untuk keperluan debugging.
Blindy
11
Saya ingin memposting komentar ini untuk melihat bahwa System.Threading.Thread.CurrentThread.ManagedThreadIdtidak akan berfungsi setidaknya saat menggunakan di a SetWindowsHookEx. Sebaliknya, kita harus mendapatkan id utas dari fungsi win32 asli GetCurrentThreadId().
King King
82

Di C # saat men-debug thread misalnya, Anda dapat melihat setiap ID utas.

Ini akan menjadi Id dari thread yang dikelola. ManagedThreadIdadalah anggota Threadagar Anda dapat memperoleh ID dari objek Thread apa pun . Ini akan memberi Anda ManagedThreadID saat ini :

Thread.CurrentThread.ManagedThreadId

Untuk mendapatkan utas OS dengan ID utas OS (bukan ManagedThreadID) , Anda dapat mencoba sedikit linq.

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

Tampaknya tidak ada cara untuk menghitung utas yang dikelola dan tidak ada hubungan antara ProcessThread dan Utas, jadi mendapatkan utas yang dikelola oleh ID itu adalah yang sulit.

Untuk detail lebih lanjut tentang threading Managed vs Unmanaged lihat arcticle MSDN ini .

badbod99
sumber
4
Mengapa tidak ada orang lain yang memberikan jawaban sederhana ini?
Stefan Steinegger
2
Ini tidak bekerja. GetCurrentProcess (). Threads mengembalikan ProcessThreadCollection, yang tidak dapat dikonversi ke Threads. Saya tidak melihat perbaikan yang mudah.
mafu
2
@ mafutrct, jawaban yang diperbarui. Properti itu harus benar-benar disebut .ProcessThreads! Terima kasih.
badbod99
2
Rekomendasikan posting ini ditulis ulang agar lebih jelas bahwa kedua id utas berbeda. Jika seseorang gagal membaca kalimat terakhir, mereka hanya akan memasukkan ManagedThreadId dan mencoba memetakannya terhadap ProcessThread.Id, membuat havok.
ShadowChaser
1
Saya telah menambahkan tautan ke acticle MSDN yang membantu menyoroti perbedaannya. Namun, pertanyaannya terkait dengan mendapatkan ID utas untuk debugging (yang dalam hal ini adalah ManagedThreadID). Saya tidak berpikir mengacaukan jawabannya dengan detail perbedaan antara OS dan thread yang dikelola berguna.
badbod99
46

Anda dapat menggunakan yang usang AppDomain.GetCurrentThreadIduntuk mendapatkan ID dari utas yang saat ini berjalan. Metode ini menggunakan PInvoke ke metode Win32 API GetCurrentThreadID, dan akan mengembalikan ID utas Windows.

Metode ini ditandai sebagai usang karena objek .NET Thread tidak sesuai dengan utas Windows tunggal, dan karenanya tidak ada ID stabil yang dapat dikembalikan oleh Windows untuk utas .NET yang diberikan.

Lihat jawaban konfigurator untuk lebih banyak alasan mengapa ini terjadi.

Paul Turner
sumber
HATI-HATI Dengan .Net Core 2.2, catat bahwa AppDomain.GetCurrentThreadId (Saya dipanggil melalui MethodInfo sebagai Obsolete) mengembalikan ID thread yang dikelola (tidak berguna untuk mencocokkan Process.GetCurrentProcess (). Koleksi thread.
brewmanz
32

Untuk mendapatkan ID OS gunakan:

AppDomain.GetCurrentThreadId()
Mark Byers
sumber
1
GetHashCode belum tentu unik! dan tidak boleh menggunakannya untuk mengidentifikasi utas.
Dror Helper
2
Anda bisa menggunakan AppDomain.GetCurrentThreadId () jika Anda menginginkan ID utas OS, tetapi beberapa utas .NET secara teori dapat berbagi utas OS yang sama. Thread.GetHashCode () dijamin untuk mengembalikan nilai yang unik untuk seluruh proses, yang mungkin Anda inginkan.
Mark Byers
3
Metode ini ditandai sebagai usang, dan dengan alasan yang bagus. Silakan lihat jawaban dan konfigurator saya untuk gambar yang lebih lengkap.
Paul Turner
3
Yah ini adalah satu-satunya cara untuk mendapatkan OS Thread ID. Dan ini harus ditandai sebagai jawaban yang benar. Meskipun begitu aku tidak akan bergantung pada ini lagi.
LolaRun
1
AppDomain.GetCurrentThreadId()sudah usang: AppDomain.GetCurrentThreadId sudah usang karena tidak memberikan ID stabil saat utas yang dikelola berjalan fibers (aka lightweight threads). Untuk mendapatkan pengidentifikasi stabil untuk utas yang dikelola, gunakan ManagedThreadIdproperti di Thread. Penggunaan:Thread.CurrentThread.ManagedThreadId
Lijo Joseph
22

Menurut MSDN :

ThreadId sistem operasi tidak memiliki hubungan tetap dengan utas yang dikelola, karena host yang tidak dikelola dapat mengontrol hubungan antara utas yang dikelola dan yang tidak dikelola. Khususnya, tuan rumah yang canggih dapat menggunakan API Hosting CLR untuk menjadwalkan banyak utas yang dikelola terhadap utas sistem operasi yang sama, atau untuk memindahkan utas yang dikelola di antara utas sistem operasi yang berbeda.

Jadi pada dasarnya, Threadobjek tidak harus sesuai dengan utas OS - itulah sebabnya ia tidak memiliki ID asli terbuka.

konfigurator
sumber
Jendela Debug / Utas di VS2010 menunjukkan "ID utas yang dikelola". Bagaimana saya bisa mendapatkan yang ini?
Pavel Radzivilovsky
1
Gunakan properti ManagedThreadID msdn.microsoft.com/en-us/library/… . Ini tidak sama dengan ID utas OS sekalipun.
konfigurator
15

Bagi yang akan diretas:

    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;
    }
ezolotko
sumber
11

Untuk menemukan id utas saat ini gunakan - `Utas.CurrentThread.ManagedThreadId '. Tetapi dalam hal ini Anda mungkin memerlukan id thread win32 saat ini - gunakan pInvoke untuk mendapatkannya dengan fungsi ini:

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

Pertama Anda harus menyimpan id utas yang dikelola dan koneksi id utas32 - gunakan kamus yang memetakan id win32 untuk utas terkelola.

Kemudian untuk menemukan utas oleh id, lakukan iterate di atas utas proses menggunakan Process.GetCurrentProcess (). Utas dan temukan utas dengan id itu:

foreach (ProcessThread thread in Process.GetCurrentProcess().Threads)
{
     var managedThread = win32ToManagedThread[thread.id];
     if((managedThread.ManagedThreadId == threadId)
     {
         return managedThread;
     }
}
Dror Helper
sumber
Saya percaya OP meminta ID OS dari utas, yang tidak sama dengan ID utas yang dikelola.
Brian Rasmussen
Kode ini tidak berfungsi: Process.Threads mengembalikan koleksi ProcessThreadobjek, ini tidak sama dengan (juga tidak mewarisi) Thread: (thread as Thread)akan mengembalikan referensi nol.
Fredrik Mörk
Saya telah memperhatikan bahwa kode kode memiliki beberapa bug - memperbaikinya coba sekarang
Dror Helper
1
Saya akhirnya menggunakan kamus yang memetakan id win32 ke utas yang dikelola.
Contango
11

Offset di bawah Windows 10 adalah 0x022C (x64-bit-Application) dan 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;
}
Reporter Handball
sumber
1
Bekerja pada Windows 7 x64 dengan SP1 juga. Namun tidak direkomendasikan. Hanya digunakan dalam pengujian sementara.
guan boshen
5

System.Threading.Thread.CurrentThread.Name

System.Threading.Thread.CurrentThread.ManagedThreadId
Manu
sumber
5

Dari kode terkelola, Anda memiliki akses ke instance dari Threadjenis untuk setiap utas yang dikelola. Threadmerangkum konsep utas OS dan pada CLR saat ini ada korespondensi satu-ke-satu dengan utas terkelola dan utas OS. Namun, ini adalah detail implementasi, yang dapat berubah di masa depan.

ID yang ditampilkan oleh Visual Studio sebenarnya adalah ID utas OS. Ini tidak sama dengan ID utas yang dikelola seperti yang disarankan oleh beberapa balasan.

The Threadtipe tidak termasuk bidang anggota IntPtr swasta yang disebut DONT_USE_InternalThread, yang menunjuk ke struktur OS yang mendasari. Namun, karena ini benar-benar detail implementasi, tidak disarankan untuk mengejar IMO ini. Dan nama semacam menunjukkan bahwa Anda tidak harus bergantung pada ini.

Brian Rasmussen
sumber
Untuk menggunakan GetThreadId Anda akan memerlukan pegangan - yang Anda dapatkan dari bidang DONT_USE.
konfigurator
Saya tahu, tetapi seperti yang saya katakan, Anda tidak dapat benar-benar mengandalkan fakta bahwa mengelola peta thread secara langsung ke thread OS, jadi saya tidak akan mengandalkannya.
Brian Rasmussen
Terima kasih banyak atas klarifikasi, dan merangkum masalahnya. Tetapi sekarang jika beberapa thread yang dikelola dapat berhubungan dengan satu thread OS (Seperti yang dinyatakan konfigurator - dan dia berterima kasih), itu berarti bahwa VS menunjukkan thread OS dan bukan Thread yang Dikelola.
LolaRun
@ OhrmaZd: Ya, VS2005 / 2008 menunjukkan ID OS untuk utas yang dikelola di jendela Utas. VS2010B2 sebenarnya menunjukkan OS dan ID yang dikelola per utas.
Brian Rasmussen
@Brian Rasmussen: Nah, itu identifikasi untuk utas yang dikelola! Terima kasih telah berbagi pengetahuan Anda.
LolaRun
4

Anda dapat menggunakan Thread.GetHashCode, yang mengembalikan ID utas yang dikelola. Jika Anda berpikir tentang tujuan GetHashCode, ini masuk akal - itu perlu pengidentifikasi unik (misalnya kunci dalam kamus) untuk objek (utas).

Sumber referensi untuk kelas Thread bersifat instruktif di sini. (Memang, implementasi .NET tertentu mungkin tidak didasarkan pada kode sumber ini, tetapi untuk tujuan debugging saya akan mengambil risiko.)

GetHashCode "menyediakan kode hash ini untuk algoritma yang memerlukan pemeriksaan cepat atas kesetaraan objek," sehingga sangat cocok untuk memeriksa kesetaraan Thread - misalnya untuk menegaskan bahwa metode tertentu sedang dijalankan pada utas yang Anda inginkan.

yoyo
sumber
4
Luar biasa, saya baru saja membuka pertanyaan berumur 5 tahun ini selama satu jam, kembali dan melihat "1 jawaban baru untuk pertanyaan ini": D
Ray
Jawaban ini diisyaratkan dalam komentar lain, tetapi akhirnya saya gunakan setelah melakukan penelitian lebih lanjut. Mungkin bukan yang diinginkan OP. Sepertinya OP tidak peduli lagi. Mungkin bermanfaat bagi orang lain. (Dan setidaknya berdasarkan sumber referensi, ini mungkin cara paling efisien untuk mendapatkan ID utas.)
yoyo
baik saya di bidang yang berbeda sekarang, tapi saat itu, kami memiliki dua ID untuk utas, id utas asli, dan id untuk utas yang dikelola, dan satu milik yang lain ... Pada prinsipnya, ID dimaksudkan untuk mengidentifikasi utas, GetHashCodes memiliki utilitas lain, dan dapat bertabrakan. Pengembang framework tidak akan mengimplementasikan ID jika kami harus menggunakan GetHashCode
LolaRun
3
@yoyo Collisions tidak merusak penggunaan kamus. Mereka dirancang untuk memiliki kemungkinan tabrakan yang rendah, bukan tabrakan sama sekali. Jika Anda hash nilai 128bit ke nilai 64bit maka setiap nilai hash akan memiliki sekitar 2 ^ 64 tabrakan. Kamus ini dirancang untuk memiliki algoritma fallback ketika tabrakan terjadi dalam kasus yang jarang terjadi.
bradgonesurfing
2
@bradgonesurfing Anda benar sekali, dan komentar saya sebelumnya salah. Kinerja kamus akan menurun dengan tabrakan hash, tetapi fungsi tetap benar. Saya minta maaf atas komentar yang menyesatkan, terima kasih telah menunjukkannya.
yoyo