Во-первых, комментарии Ганса совершенно верны: вы плохо придумываете свое собственное вращение. Не делай этого!
Тем не менее, ваш вопрос не о том, должен ли повторно реализовать WaitOne, а, скорее, о том, как WaitOne был реализован людьми, у которых его не было, потому что он еще не был написан . Вполне разумно рассмотреть этот вопрос; такие функции не магические и были реализованы людьми, так как же они это сделали?
Это детали реализации, и у меня нет удобного исходного кода для среды выполнения; фактическая реализация находится в собственной функции с именем WaitOneNative
. Тем не менее, я могу дать вам несколько мыслей.
Во-первых, вы правы, отметив, что Thread.Yield
является более примитивной операцией, и поэтому ее можно использовать как часть стратегии для создания операции более высокого уровня, такой как WaitOne
. Но на практике это, вероятно, не будет использоваться в наивной манере, которую вы описываете, по нескольким причинам:
Thread.Yield
действительно создает барьер, но из кода на 100% не очевидно, что чтение bool не было опущено или что запись не может быть отложена. Мы хотели бы сделать очень, очень уверенным, что запись bool была подхвачена, и что введение барьера не ухудшило производительность.
Thread.Yield
уступает управление любому готовому потоку на текущем процессоре . Что произойдет, если на текущем процессоре нет готового потока? Возможно, обдумайте это. Что удерживает этот код от нагрева всего процессора? Что произойдет, если поток, который собирается выполнить запись, находится на другом процессоре? Каковы все возможные сценарии, связанные с голоданием нити и т. Д.
Рассмотрим этот сценарий: у нас есть многопоточный процессор с тремя потоками, Alpha, Bravo и Charlie, а Alpha и Bravo в настоящее время выполняются в CPU. Альфа имеет в своем кванте 10 миллионов наносекунд, она видит, что флаг ложен, и уступает Чарли остаток своего кванта Спустя одну наносекунду, Браво устанавливает флаг. Мы просто взяли на себя полную стоимость переключения контекста, и Alpha отказалась от возможности выполнить десять миллионов наносекунд работы! «Альфе» было бы лучше, если бы она ждала несколько десятков из своих десяти миллионов наносекунд, а не взяла на себя огромные затраты на переключение контекста. Это те сценарии, которые вы должны учитывать при разработке нового многопоточного примитива . Просто получить правильный поток управления не достаточно хорошо; вы принимаете неверное решение на горячем пути и можете снизить производительность в тысячи или миллионы раз.
и т. Д.
Но подождите, становится хуже. Есть ли более тонкие проблемы, которые WaitOne
должен решить?
Конечно. У CLR есть инварианты, которые он должен поддерживать. Вы должны помнить, что CLR был изначально изобретен как расширение COM , и базовая реализация глубоко внедрена в мир COM. В частности, все правила о распределении по-прежнему применяются. WaitOne эффективно усыпляет поток, но это может привести к проблемам с маршаллером. Статья Криса Брамма об этом особенно страшна и выявляет:
https://blogs.msdn.microsoft.com/cbrumme/2004/02/02/apartments-and-pumping-in-the-clr/
Прочтите это, посмотрите, сможете ли вы понять все это. Я читал его десятки раз с 2004 года, и раньше я был профессиональным программистом COM, и я получаю, возможно, 80% этого. Это сложная вещь, и если вы ее не понимаете, вы не можете написать правильную реализацию WaitOne
, которая соответствует потребностям CLR.