-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Background and Motivation
We added UnsafeStart in this PR #46181 because we needed to lazily create thread pool threads and the timer thread on the default execution context. UnsafeStart avoids capturing the current execution context and restoring it when the thread runs. There are other places where we create threads that could use similar logic:
runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs
Lines 160 to 173 in 637e3aa
bool suppressFlow = !ExecutionContext.IsFlowSuppressed(); try { if (suppressFlow) ExecutionContext.SuppressFlow(); Thread thread = new Thread(s => ((SocketAsyncEngine)s!).EventLoop()); thread.IsBackground = true; thread.Name = ".NET Sockets"; thread.Start(this); } finally { if (suppressFlow) ExecutionContext.RestoreFlow(); } runtime/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.OSX.cs
Lines 202 to 207 in 637e3aa
new Thread(args => { object[] inputArgs = (object[])args!; WatchForFileSystemEventsThreadStart((ManualResetEventSlim)inputArgs[0], (SafeEventStreamHandle)inputArgs[1]); }) { IsBackground = true }.Start(new object[] { runLoopStarted, eventStream }); runtime/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Linux.cs
Line 299 in 637e3aa
Task.Factory.StartNew(obj => ((RunningInstance)obj!).ProcessEvents(),
These are places that should start on the default execution context.
Proposed API
namespace System.Threading
{
public class Thread
{
+ void UnsafeStart();
+ void UnsafeStart(object? parameter);
}
Usage Examples
var local = new AsyncLocal<int>();
local.Value = 10;
var thread= new Thead(() =>
{
var value = local.Value;
while (true)
{
Console.WriteLine(value++);
Thread.Sleep(5000);
}
});
thread.UnsafeStart();
Alternative Designs
Passing a boolean to the thread constructor but that seemed like a bad idea since Start is the thing capturing the execution.
Risks
None.