Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions release-notes/10.0/preview/preview7/libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,84 @@ Here's a summary of what's new in .NET Libraries in this preview release:
## Feature

Something about the feature

## Launch Windows processes in new process group
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dotnet/area-system-diagnostics-process


For Windows, you can now use `ProcessStartInfo.CreateNewProcessGroup` to launch a process in a separate PG. This allows you to send isolated signals to child processes which could otherwise take down the parent without proper handling. Sending signals is convenient to avoid forceful termination.

```csharp
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

class Program
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following example is complex, but correct. And it will most likely match the real world use case.

{
static void Main(string[] args)
{
bool isChildProcess = args.Length > 0 && args[0] == "child";
if (!isChildProcess)
{
var psi = new ProcessStartInfo
{
FileName = Environment.ProcessPath,
Arguments = "child",
CreateNewProcessGroup = true,
};

using Process process = Process.Start(psi)!;
Thread.Sleep(5_000);

GenerateConsoleCtrlEvent(CTRL_C_EVENT, (uint)process.Id);
process.WaitForExit();

Console.WriteLine("Child process terminated gracefully, continue with the parent process logic if needed.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we read the log.txt file output and display it here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to show the need of properly dispose unmanaged resources (I'm open to better examples!). I don't think we need to read it back in the parent branch.

}
else
{
// you need to call SetConsoleCtrlHandler this way if you want to handle Ctrl+C in the child process,
// see https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw#remarks
SetConsoleCtrlHandler((IntPtr)null, false);

Console.WriteLine("Greetings from the child process! I need to be gracefully terminated, send me a signal!");

bool stop = false;

var registration = PosixSignalRegistration.Create(PosixSignal.SIGINT, ctx =>
{
stop = true;
ctx.Cancel = true;
Console.WriteLine("Received CTRL+C, stopping...");
});

StreamWriter sw = File.AppendText("log.txt");
int i = 0;
while (!stop)
{
Thread.Sleep(1000);
sw.WriteLine($"{++i}");
Console.WriteLine($"Logging {i}...");
}

// Clean up
sw.Dispose();
registration.Dispose();

Console.WriteLine("Thanks for not killing me!");
}
}

private const int CTRL_C_EVENT = 0;
private const int CTRL_BREAK_EVENT = 1;

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetConsoleCtrlHandler(IntPtr handler, [MarshalAs(UnmanagedType.Bool)] bool Add);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent, uint dwProcessGroupId);
}
```