Table of Contents

Class StopSignals

Namespace
OptunaSharp
Assembly
OptunaSharp.dll

Turns the first Ctrl+C (SIGINT) or SIGTERM the process receives into a cancelled Token, so that a console program stops Study.Optimize gracefully: no trial starts after the signal, the trials in flight finish and are stored, and Optimize throws OperationCanceledException. A second signal ends the process as it would without this class. OptunaSharp only, and opt-in: OptunaSharp never installs a handler by itself, because a signal handler is process-wide.

public sealed class StopSignals : IDisposable
Inheritance
StopSignals
Implements
Inherited Members

Examples

using var signals = StopSignals.Listen();
study.Optimize(Objective, nTrials: 500, nJobs: 4, ct: signals.Token);

Remarks

Why. By default .NET ends the process at Ctrl+C or SIGTERM, and the trials in flight stay RUNNING in a persistent storage: a journal never fails them, and an RDB storage with heartbeats fails them later as stale. Python Optuna raises KeyboardInterrupt instead; at n_jobs above 1 its trials in flight finish first, and at n_jobs 1 the trial the interrupt lands in is stored FAIL (THREADING.md ยง3.4). With this class the trials in flight finish, and an objective that observes CancellationToken is stored FAIL, as in Python.

Cost. None until a signal arrives: the handlers are operating-system callbacks registered through PosixSignalRegistration. Measured on 2026-11-07 over 10 idle seconds, a process used the same CPU with and without them (Windows creates the handler thread only when the signal comes; Linux adds one runtime thread asleep in a blocking read).

Containers. docker stop and Kubernetes send SIGTERM, then kill the process after a grace period (10 s and 30 s by default): the trials in flight must finish within it. On Windows the runtime raises SIGTERM for the console's shutdown events.

Hosts. A .NET Generic Host already handles both signals; pass its IHostApplicationLifetime.ApplicationStopping token to Optimize instead of using this class.

Lifetime. Dispose() unhooks the handlers, after which a signal takes its default action again; the token stays valid and keeps its state. Several instances may listen at once: the first signal cancels every token, and the second ends the process.

Properties

Token

Cancelled by the first SIGINT or SIGTERM after Listen(); pass it as Optimize's ct.

public CancellationToken Token { get; }

Property Value

CancellationToken

Remarks

Readable after Dispose(), which leaves its state unchanged.

Methods

Dispose()

Unhooks both handlers, so that the next signal takes its default action. Calling it again does nothing.

public void Dispose()

Listen()

Starts listening for SIGINT (Ctrl+C) and SIGTERM. Dispose the result, usually with using, to stop.

public static StopSignals Listen()

Returns

StopSignals

A listener whose Token is cancelled by the first signal.

Exceptions

PlatformNotSupportedException

The platform has no signal handling (a browser runtime).

IOException

The operating system refuses the registration.