Lấy ID luồng từ một luồng


319

Trong C # khi gỡ lỗi các luồng chẳng hạn, bạn có thể thấy ID của từng luồng.

Tôi không thể tìm ra cách để có được chủ đề tương tự, lập trình. Tôi thậm chí không thể có được ID của luồng hiện tại (trong thuộc tính của Thread.currentThread).

Vì vậy, tôi tự hỏi làm thế nào Visual Studio có được ID của các luồng, và có cách nào để có được xử lý của luồng với id 2345, chẳng hạn?

Câu trả lời:


437

GetThreadIdtrả về ID của một luồng gốc đã cho. Có nhiều cách để làm cho nó hoạt động với các luồng được quản lý, tôi chắc chắn, tất cả những gì bạn cần tìm là xử lý luồng và chuyển nó đến chức năng đó.

GetCurrentThreadId trả về ID của luồng hiện tại.

GetCurrentThreadIdđã bị phản đối kể từ .NET 2.0: cách được đề xuất là thuộc Thread.CurrentThread.ManagedThreadIdtính.


87
Kể từ khi tôi tìm thấy cái này, đã gõ nó, và sau đó được thông báo rằng nó không dùng nữa, cách hiện tại để làm điều này là Thread.CảnThread.ManagedThreadId
James

3
ManagedThreadId không phải là một cách tiếp cận mạnh mẽ để xác định các luồng khi id thuộc tính ManagedThreadId được ứng dụng của bạn sử dụng lại. Vì vậy, nó không phải là một định danh đáng tin cậy cho các luồng trong một số trường hợp và bạn sẽ gặp ngoại lệ: "Một mục có cùng khóa đã được thêm vào." tại dòng ... Đặt cho chủ đề một tên duy nhất khi bạn tạo nó.
Forer

15
Có một số lời khuyên rất tệ xung quanh bài viết này. Một vài người đang khuyến nghị sử dụng "ManagedThreadId" để xác định một chuỗi. Tôi đã chỉnh sửa bài đăng để xóa đề xuất - điều mà rất ít người chỉ ra là có nhiều loại id luồng khác nhau. ID luồng được quản lý không giống với id luồng không được quản lý và nếu mọi người sao chép và dán mã đó, một số lỗi đồng bộ hóa rất tinh vi có thể xảy ra. Tài liệu về MSDN cho lớp Thread rất rõ ràng về điều này. Xem các nhận xét ở cấp lớp.
ShadowChaser

3
Mặc dù vậy, bạn không đồng bộ hóa trên ID, bạn sử dụng các nguyên hàm đồng bộ hóa như mutexes. Điều này chỉ dành cho mục đích gỡ lỗi.
Blindy

11
Tôi muốn đăng bình luận này để thông báo rằng System.Threading.Thread.CurrentThread.ManagedThreadIdsẽ không hoạt động ít nhất khi sử dụng trong a SetWindowsHookEx. Thay vào đó, chúng ta phải lấy id luồng từ hàm win32 gốc GetCurrentThreadId().
Vua King

82

Trong C # khi gỡ lỗi các luồng chẳng hạn, bạn có thể thấy ID của từng luồng.

Đây sẽ là Id của các chủ đề được quản lý. ManagedThreadIdlà thành viên Threadđể bạn có thể lấy Id từ bất kỳ đối tượng Thread nào . Điều này sẽ giúp bạn có ManagedThreadID hiện tại :

Thread.CurrentThread.ManagedThreadId

Để có được một luồng hệ điều hành bằng ID luồng của hệ điều hành (không phải ManagedThreadID) , bạn có thể thử một chút linq.

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

Dường như không có cách nào để liệt kê các luồng được quản lý và không có mối quan hệ nào giữa ProcessThread và Thread, do đó, việc nhận được một luồng được quản lý bởi Id của nó là một điều khó khăn.

Để biết thêm chi tiết về phân luồng Managed vs Unmanaged, hãy xem cung này MSDN .


4
Tại sao không ai khác đưa ra câu trả lời đơn giản này?
Stefan Steinegger

2
Điều này không hoạt động. GetCienProcess (). Chủ đề trả về một ProcessThreadCollection, không thể chuyển đổi thành Chủ đề. Tôi không thấy một sửa chữa dễ dàng.
mafu

2
@ mafutrct, cập nhật câu trả lời. Tài sản đó thực sự nên được gọi là .ProcessThreads! Cảm ơn.
badbod99

2
Đề nghị bài viết này được viết lại để làm rõ hơn rằng hai id id khác nhau. Nếu ai đó không đọc được câu cuối cùng, họ sẽ chỉ cắm ManagedThreadId và cố gắng ánh xạ nó tới ProcessThread.Id, tạo havok.
ShadowChaser

1
Tôi đã thêm một liên kết đến một biểu tượng MSDN hữu ích làm nổi bật sự khác biệt. Tuy nhiên, câu hỏi liên quan đến việc lấy ID luồng để gỡ lỗi (trong trường hợp này là ManagedThreadID). Tôi không nghĩ lộn xộn câu trả lời với các chi tiết về sự khác biệt giữa hệ điều hành và các luồng được quản lý là hữu ích.
badbod99

46

Bạn có thể sử dụng deprecated AppDomain.GetCurrentThreadIdđể lấy ID của luồng hiện đang chạy. Phương pháp này sử dụng phương pháp PInvoke cho Win32 API GetCurrentThreadIDvà sẽ trả về ID luồng của Windows.

Phương thức này được đánh dấu là không dùng nữa vì đối tượng .NET Thread không tương ứng với một luồng Windows duy nhất và do đó không có ID ổn định nào có thể được Windows trả về cho một luồng .NET nhất định.

Xem câu trả lời của nhà cấu hình để biết thêm lý do tại sao đây là trường hợp.


THẬN TRỌNG Với .Net Core 2.2, lưu ý rằng AppDomain.GetCienThreadId (Tôi đã gọi qua MethodInfo là Lỗi thời) trả về ID luồng được quản lý (vô dụng để khớp với Process.GetCienProcess (). Bộ sưu tập chủ đề.
brewmanz

32

Để lấy ID hệ điều hành, hãy sử dụng:

AppDomain.GetCurrentThreadId()

1
GetHashCode không nhất thiết phải là duy nhất! và không nên sử dụng nó để xác định một chủ đề.
Dror Helper

2
Bạn có thể sử dụng AppDomain.GetCienThreadId () nếu bạn muốn ID luồng của hệ điều hành, nhưng về lý thuyết, nhiều luồng .NET có thể chia sẻ cùng một luồng hệ điều hành. Thread.GetHashCode () được đảm bảo trả về một giá trị duy nhất trên toàn quy trình, đó là những gì bạn có thể muốn.
Mark Byers

3
Phương pháp này được đánh dấu là không dùng nữa, và với lý do chính đáng. Xin vui lòng xem câu trả lời của tôi và cấu hình cho hình ảnh đầy đủ hơn.
Paul Turner

3
Chà, đây là cách duy nhất để đến ID Thread của hệ điều hành. Và điều này nên được đánh dấu là câu trả lời chính xác. Mặc dù tôi sẽ không dựa vào điều này nữa.
LolaRun

1
AppDomain.GetCurrentThreadId()đã lỗi thời: AppDomain.GetCurrentThreadId đã bị phản đối vì nó không cung cấp Id ổn định khi các luồng được quản lý đang chạy fibers (aka lightweight threads). Để có được một định danh ổn định cho một chủ đề được quản lý, hãy sử dụng thuộc ManagedThreadIdtính trên Thread. Cách sử dụng:Thread.CurrentThread.ManagedThreadId
Lijo Joseph

22

Theo MSDN :

Một ThreadId của hệ điều hành không có mối quan hệ cố định với một luồng được quản lý, bởi vì một máy chủ không được quản lý có thể kiểm soát mối quan hệ giữa các luồng được quản lý và không được quản lý. Cụ thể, một máy chủ tinh vi có thể sử dụng API Hosting CLR để lên lịch nhiều luồng được quản lý theo cùng một luồng của hệ điều hành hoặc để di chuyển một luồng được quản lý giữa các luồng của hệ điều hành khác nhau.

Về cơ bản, Threadđối tượng không nhất thiết phải tương ứng với một luồng hệ điều hành - đó là lý do tại sao nó không có ID gốc được phơi bày.


Cửa sổ Gỡ lỗi / Chủ đề trong VS2010 hiển thị "ID luồng được quản lý". Làm thế nào tôi có thể có được cái này?
Pavel Radzivilovsky

1
Sử dụng thuộc tính ManagedThreadID msdn.microsoft.com/en-us/l Library / . Điều này không giống với ID luồng của hệ điều hành.
cấu hình

15

Đối với những người sắp hack:

    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

Để tìm Id luồng hiện tại, hãy sử dụng - `Thread.CảnThread.ManagedThreadId '. Nhưng trong trường hợp này, bạn có thể cần id luồng win32 hiện tại - sử dụng pInvoke để lấy nó với chức năng này:

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

Trước tiên, bạn sẽ cần lưu id chủ đề được quản lý và kết nối id chủ đề win32 - sử dụng từ điển ánh xạ id win32 sang chủ đề được quản lý.

Sau đó, để tìm một chủ đề bởi id của nó lặp đi lặp lại qua chủ đề của quy trình bằng cách sử dụng Process.GetCienProcess (). Chủ đề và tìm chủ đề với id đó:

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

Tôi tin rằng OP đang yêu cầu ID hệ điều hành của luồng, không giống với ID luồng được quản lý.
Brian Rasmussen

Mã này không hoạt động: Process.Threads trả về một bộ sưu tập các ProcessThreadđối tượng, điều này không giống với (cũng không kế thừa) Thread: (thread as Thread)sẽ trả về một tham chiếu null.
Fredrik Mörk

Tôi đã nhận thấy rằng mã mã có một vài lỗi - đã sửa nó ngay bây giờ
Dror Helper

1
Tôi đã kết thúc bằng cách sử dụng một từ điển ánh xạ id win32 đến một chủ đề được quản lý.
Contango

11

Giá trị bù trong Windows 10 là 0x022C (x64-bit-Application) và 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
Hoạt động trên Windows 7 x64 với SP1. Không được đề nghị mặc dù. Chỉ sử dụng trong thử nghiệm tạm thời.
guan boshen

5

System.Threading.Thread.C HiệnThread.Name

System.Threading.Thread.CurrentThread.ManagedThreadId

5

Từ mã được quản lý, bạn có quyền truy cập vào các thể hiện của Threadloại cho từng luồng được quản lý. Threadđóng gói khái niệm về một luồng hệ điều hành và kể từ CLR hiện tại, có một sự tương ứng một-một với các luồng được quản lý và các luồng của hệ điều hành. Tuy nhiên, đây là một chi tiết thực hiện, có thể thay đổi trong tương lai.

ID được hiển thị bởi Visual Studio thực sự là ID luồng của hệ điều hành. Điều này không giống với ID luồng được quản lý như được đề xuất bởi một số câu trả lời.

Các Threadloại này bao gồm một trường thành viên IntPtr tin gọi là DONT_USE_InternalThread, mà điểm đến cấu trúc hệ điều hành cơ bản. Tuy nhiên, vì đây thực sự là một chi tiết triển khai nên không nên theo đuổi IMO này. Và loại tên chỉ ra rằng bạn không nên dựa vào điều này.


Để sử dụng GetThread, bạn cần có tay cầm - thứ bạn nhận được từ trường DONT_USE.
cấu hình

Tôi biết, nhưng như tôi đã nói, bạn không thể thực sự tin vào thực tế là các luồng được quản lý ánh xạ trực tiếp tới các luồng của hệ điều hành, vì vậy tôi sẽ không tin vào điều đó.
Brian Rasmussen

Cảm ơn rất nhiều vì đã làm rõ, và tóm tắt vấn đề. Nhưng bây giờ nếu nhiều luồng được quản lý có thể tương ứng với một luồng HĐH duy nhất (Như cấu hình đã nêu - và anh ấy đã cảm ơn), điều đó có nghĩa là VS đang hiển thị các luồng của HĐH chứ không phải Chủ đề được quản lý.
LolaRun

@OhrmaZd: Có, VS2005 / 2008 hiển thị ID hệ điều hành cho các luồng được quản lý trong cửa sổ Chủ đề. VS2010B2 thực sự hiển thị cả HĐH và ID được quản lý trên mỗi luồng.
Brian Rasmussen

@Brian Rasmussen: Bây giờ đó là một nhận dạng cho một chủ đề được quản lý! Cảm ơn đã chia sẻ kiến ​​thức của bạn.
LolaRun

4

Bạn có thể sử dụng Thread.GetHashCode, trả về ID luồng được quản lý. Nếu bạn nghĩ về mục đích của GetHashCode, điều này có ý nghĩa tốt - nó cần phải là một định danh duy nhất (ví dụ: khóa trong từ điển) cho đối tượng (luồng).

Nguồn tham khảo cho lớp Thread là hướng dẫn ở đây. (Được cấp, một triển khai .NET cụ thể có thể không dựa trên mã nguồn này, nhưng với mục đích gỡ lỗi, tôi sẽ nắm lấy cơ hội của mình.)

GetHashCode "cung cấp mã băm này cho các thuật toán cần kiểm tra nhanh sự bằng nhau của đối tượng", vì vậy nó rất phù hợp để kiểm tra tính bằng của Thread - ví dụ để khẳng định rằng một phương thức cụ thể đang thực thi trên luồng mà bạn muốn nó gọi từ đó.


4
Thật tuyệt vời, tôi vừa mở câu hỏi 5 tuổi này trong một giờ, quay lại và thấy "1 câu trả lời mới cho câu hỏi này": D
Ray

Câu trả lời này đã được gợi ý trong một bình luận khác, nhưng đó là những gì tôi đã sử dụng sau khi nghiên cứu thêm. Có thể không phải là những gì OP muốn. Có khả năng OP không quan tâm nữa. Có thể hữu ích cho người khác. (Và ít nhất là dựa trên nguồn tham chiếu, đây có thể là cách hiệu quả nhất để lấy ID luồng.)
yoyo

Hiện tại tôi đang ở một lĩnh vực khác, nhưng trước đó, chúng tôi có hai ID cho một luồng, id của luồng gốc và id cho luồng được quản lý và một thuộc về một chủ đề khác ... Chủ yếu, ID được dùng để xác định các luồng, GetHashCodes có tiện ích khác và có thể va chạm. Các nhà phát triển khung sẽ không triển khai ID nếu chúng tôi phải sử dụng GetHashCode
LolaRun

3
@yoyo Va chạm không phá vỡ sử dụng từ điển. Chúng được thiết kế để có xác suất va chạm thấp, không có va chạm nào cả. Nếu bạn băm một giá trị 128 bit thành giá trị 64 bit thì mỗi giá trị băm sẽ có khoảng 2 ^ 64 va chạm. Từ điển được thiết kế để có thuật toán dự phòng khi xảy ra va chạm trong trường hợp hiếm gặp.
bradgonesurfing

2
@bradgonesurfing Bạn hoàn toàn đúng, và nhận xét trước đây của tôi là sai. Hiệu suất từ ​​điển sẽ giảm với các va chạm băm, nhưng chức năng vẫn đúng. Tôi xin lỗi vì nhận xét sai lệch, cảm ơn vì đã chỉ ra điều đó.
yoyo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.