Как да получа идентификатора на текущата нишка без AppDomain.GetCurrentThreadId(), така че действително да работи?

Тъй като AppDomin.GetCurrentThreadId() е остарял

„AppDomain.GetCurrentThreadId е остарял, защото не предоставя стабилен идентификатор, когато управляваните нишки се изпълняват на влакна (известни още като леки нишки). За да получите стабилен идентификатор за управлявана нишка, използвайте свойството ManagedThreadId на Thread. http://go.microsoft.com/fwlink/?linkid=14202"

Опитах се да не го използвам. Въпреки това, обяснението, че „Thread.CurrentThread.ManagedThreadId“ ще работи, е безполезно, защото не предоставя идентификатор на нишка Win32, който ми е необходим за извиквания на Win32. Така че аз го внедрих сам, както следва.

public sealed class AppDomainExtender
{
    public static int GetCurrentThreadId_New()
    {
        return Process.GetCurrentProcess().Threads.OfType<ProcessThread>().SingleOrDefault(x => x.ThreadState == System.Diagnostics.ThreadState.Running).Id;
    }
}

Сега има два проблема.

  • Ако щеше да работи, нямаше ли да направи точно същото като AppDomain.GetCurrentThreadId?
  • Не работи поради причината, че изпълняваната нишка може да се промени, докато преминава през цикъла SingleOrDefault. Това поведение е странно, но току-що ми даде InvalidOperationException („Поредица съдържа повече от един елемент“). Очевидно това се случва например при използване на множество настолни компютри (предполагам, че това е възможно само чрез копиране на нишката, която изпълнява цикъла, на друг идентификатор).

Въпроси:

  1. Дали AppDomain.GetCurrentThreadId е фалшиво деклариран като остарял?
  2. Как може да се направи изразът "Process.GetCurrentProcess().Threads.OfType().SingleOrDefault(x => x.ThreadState == System.Diagnostics.ThreadState.Running).Id" атомен, или дори е възможно?

person xamid    schedule 26.08.2014    source източник
comment
Опитахте ли да PInvoke метода GetCurrentThreadId()?   -  person timothy.B    schedule 26.08.2014
comment
Внедрявам приложение за автоматизация на потребителския интерфейс, базирано на екранни снимки, в Windows 7, има толкова много съществено използване на user32.dll, gdi32.dll и kernel32.dll, че не може да бъде пропуснато. Не прави ли PIvoked 'GetCurrentThreadId()' абсолютно същото като 'AppDomain.GetCurrentThreadId()'?   -  person xamid    schedule 26.08.2014
comment
pinvoke.net/default.aspx/kernel32.getcurrentthreadid   -  person timothy.B    schedule 26.08.2014


Отговори (1)


Отказът от AppDomain.GetCurrentThreadId() е неудобна истина, със сигурност не е „фалшива“ декларация. Започвайки от .NET 2.0, връзката между .NET нишка и нишка на операционната система беше прекъсната. Персонализираният CLR хост е свободен да внедрява нишки по начина, по който сметне за добре, чрез прилагане на Интерфейс на IClrTask. Или с други думи, нямате гаранция, че две различни нишки .NET използват различни нишки на операционната система с различни идентификатори на нишки.

Това като цяло беше популярно нещо за правене през 1990-те и началото на 2000-те, като се използваха имена като „леки нишки“, съвместни процедури, влакна, „зелени нишки“ и т.н. Идеята беше да се избегнат превключванията на контекста на нишката от операционна система и превключване на контекста, процесорът се регистрира в софтуера. SQL Server беше основният бенефициент на тази функция, той има вградена поддръжка за "fiber mode".

Докато екипът на SQL Server получи функцията, те в крайна сметка решиха да не я доставят. Те изоставиха проекта, когато не можаха да го направят достатъчно стабилен. Проблем, който вероятно е вдъхновил тази статия, публикувана в същия година проектът им трябваше. Това не е пробвано отново. Ни най-малко, защото функцията беше остаряла от многоядрената революция. Цената на контекстния превключвател в съвременните ядра е доминирана от състоянието на кеш паметта на процесора, невъзможно е да се конкурира с всяко ядро, което има собствен L1 и L2 кеш.

Не знам за нито един CLR хост, който действително внедрява IClrTask, провалът на екипа на SQL Server със сигурност беше голям червен флаг. Това обаче не изключва възможността видът сценарий, за който може да искате да се притеснявате, да изпълнява вашия код в контекста на голямо неуправляемо приложение, което поддържа скриптове на управляван език. Една CAD програма би била типичен пример за това.

Ще бъдете мъртви във водата в много малко вероятния случай, когато вашият код действително ще работи в този контекст, така че настройте лазера си да зашеметява и продължете напред. Отвъд необходимостта да се примирите с предупреждението за остаряване, най-разумното решение е да pinvoke GetCurrentThreadId(). Много е бързо.

person Hans Passant    schedule 26.08.2014
comment
Беше много интересно, благодаря! Въпреки че според мен .Net влакната всъщност не са нишки и следователно „GetCurrentThreadId()“ не трябва да се маркира като остаряла. Освен това тези влакна не трябва да се наричат ​​нишки, те действат просто като съпрограмми. - person xamid; 26.08.2014
comment
Това е само мнение, което не променя факта. Ще трябва да направите своя случай с Microsoft, за да получите желаните промени . - person Hans Passant; 26.08.2014
comment
Всъщност екипът на CLR искаше да поддържа NT Fibers за 2.0, но в крайна сметка не можа да го направи, вижте Duffy's Concurrent Programming on Windows p449. - person Chris O; 16.07.2015