UCILoader 1.1.2
Small C++ library that allows user to connect to a chess engines via UCI protocol.
Loading...
Searching...
No Matches
UCILoader::ProcessWrapper Class Referenceabstract

Cross-platform wrapper for managing a chess engine process. More...

#include <ProcessWrapper.h>

Inherited by UnixProcessWrapper, and WindowsEngineProcess.

Public Member Functions

virtual ~ProcessWrapper ()=default
 Virtual destructor that ensures listening thread is properly joined.
 
virtual std::shared_ptr< AbstractPipeWritergetWriter ()=0
 Get the pipe writer for the process's standard input.
 
virtual void kill ()=0
 Immediately terminate the underlying process.
 
virtual bool isAlive () const =0
 Check if the process is alive using OS calls.
 
virtual bool healthCheck ()
 Perform a safe health check of the process.
 
void listen (std::function< void(std::string)> lineReceiver, std::function< void()> onCrash=[](){})
 Start a background listening thread for reading process output lines.
 

Protected Member Functions

virtual std::shared_ptr< AbstractPipeReadergetReader ()=0
 Get the pipe reader for the process's standard output.
 

Detailed Description

Cross-platform wrapper for managing a chess engine process.

ProcessWrapper provides platform-independent abstraction for creating, monitoring, and communicating with external processes (chess engines). It handles:

  • Process creation and lifecycle management
  • Bidirectional I/O through pipes (stdin/stdout)
  • Process health monitoring
  • Asynchronous line-based input listening with callbacks

While ProcessWrapper is typically passed to an EngineInstance for automatic management, it can also be used independently for custom use cases (see proxy example in examples/ folder).

Platform-Specific Implementations:

  • Windows: Uses WinProcessWrapper with Windows pipes
  • Unix/Linux: Uses UnixProcessWrapper with POSIX pipes

Typical Usage:

// Create process
auto process = openProcess({"stockfish.exe"}, "/");
// Set up line-based listening
process->listen(
[](const std::string& line) {
std::cout << "Engine: " << line << std::endl;
},
[]() {
std::cerr << "Engine crashed!" << std::endl;
}
);
// Send data to process
process->getWriter()->write("uci\n", 4);
// Check if process is healthy
if (!process->healthCheck()) {
std::cout << "Engine terminated" << std::endl;
}
void listen(std::function< void(std::string)> lineReceiver, std::function< void()> onCrash=[](){})
Start a background listening thread for reading process output lines.
Definition: ProcessWrapper.h:200
See also
EngineInstance for typical usage
openProcess for creating instances

Member Function Documentation

◆ getReader()

virtual std::shared_ptr< AbstractPipeReader > UCILoader::ProcessWrapper::getReader ( )
protectedpure virtual

Get the pipe reader for the process's standard output.

Returns
Shared pointer to AbstractPipeReader connected to stdout

This is a protected method implemented by platform-specific subclasses. Used internally by listen() to set up line reading from the process.

See also
AbstractPipe.h for pipe abstraction details

◆ getWriter()

virtual std::shared_ptr< AbstractPipeWriter > UCILoader::ProcessWrapper::getWriter ( )
pure virtual

Get the pipe writer for the process's standard input.

Returns
Shared pointer to AbstractPipeWriter connected to stdin

Used to send commands to the process. The returned writer can be used independently at any time after construction.

See also
AbstractPipe.h for pipe abstraction details

◆ healthCheck()

virtual bool UCILoader::ProcessWrapper::healthCheck ( )
inlinevirtual

Perform a safe health check of the process.

Returns
True if the process is alive and healthy, false if it has terminated or crashed

Unlike isAlive(), this method handles platform-specific edge cases:

  • On first detection of process death, immediately kills it to prevent dangling processes
  • Subsequent calls return the cached failure state to avoid repeated OS calls

Safe to call repeatedly without performance penalty.

◆ isAlive()

virtual bool UCILoader::ProcessWrapper::isAlive ( ) const
pure virtual

Check if the process is alive using OS calls.

Returns
True if the process is still running, false otherwise
Warning
On Windows, this may return false while the process is still somewhat running, potentially leading to dangling processes. Use healthCheck() instead for more robust checking.
See also
healthCheck() for the safer alternative

◆ kill()

virtual void UCILoader::ProcessWrapper::kill ( )
pure virtual

Immediately terminate the underlying process.

Uses platform-specific OS calls to forcefully kill the process. This is safe to call multiple times.

◆ listen()

void UCILoader::ProcessWrapper::listen ( std::function< void(std::string)>  lineReceiver,
std::function< void()>  onCrash = [](){} 
)
inline

Start a background listening thread for reading process output lines.

Parameters
lineReceiverCallback function invoked for each line received from the process. The string is passed without the trailing newline character.
onCrashOptional callback invoked when the listening thread terminates due to pipe closure (process crash or EOF). Defaults to a no-op lambda.

This method spawns a background thread that continuously:

  1. Reads lines from the process's stdout via PipeScanner
  2. Invokes lineReceiver callback for each complete line
  3. If pipe closes, invokes onCrash callback and terminates

Important Notes:

  • This method must be called only once per ProcessWrapper instance
  • The callbacks are invoked from the listening thread, not the calling thread
  • Use thread-safe mechanisms (locks, atomics) in callbacks if accessing shared state
  • The listening thread continues until the process exits or pipe closes

Usage Example:

process->listen(
[&state](const std::string& line) {
std::lock_guard<std::mutex> lock(state.mutex);
state.lastLine = line;
},
[&state]() {
std::lock_guard<std::mutex> lock(state.mutex);
state.processCrashed = true;
}
);

The documentation for this class was generated from the following file: