Keep boost.process alive outside of the function is was called from - c++

I'm using Visual Studio 2019 on Windows 10, using the boost.process library. I'm trying to make chess, and I'm using the stockfish engine as a separate executable. I need the engine to run throughout the entirety of the game, as that's how it's designed to be used.
Currently I have in ChessGame.h
class ChessGame
{
public:
void startStockFish();
void beginGame();
void parseCommand(std::string cmd);
private:
boost::process::child c;
boost::process::ipstream input;
boost::process::opstream output;
}
And in ChessGame.cpp
#include ChessGame.h
void ChessGame::startStockFish()
{
std::string exec = "stockfish_10_x32.exe";
std::vector<std::string> args = { };
boost::process::child c(exec, args, boost::process::std_out > input,
boost::process::std_in < output);
//c.wait()
}
void ChessGame::beginGame()
{
parseCommand("uci");
parseCommand("ucinewgame");
parseCommand("position startpos");
parseCommand("go");
}
void ChessGame::parseCommand(std::string cmd)
{
output << cmd << std::endl;
std::string line;
while (std::getline(input, line) && !line.empty())
{
std::cout << line << std::endl;
}
}
And in main.cpp
ChessGame chessGame = ChessGame(isWhite); //isWhite is a boolean that control who the player is, irrelevent to the question
//std::thread t(&ChessGame::startStockFish, chessGame);
chessGame.startStockFish();
chessGame.beginGame();
The problem is that I believe as soon as the function startStockFish finishes it terminates c, as nothing is outputted to the terminal as described above, but if I use beginGame() within startStockFish() it outputs as expected. Also, if I uncomment the line c.wait() and the funtion waits for stockfish to exit, it gets stuck as stockfish never gets the exit command. If I instead try running startStockFish on a separate thread in main (as seen above) I
get the following two errors:
the argument to a feature-test macro must be a simple identifier.
In file 'boost\system\detail\config.hpp' line 51
and
'std::tuple::tuple': no overloaded function takes 2 arguments.
In file 'memory' line 2042
Also, I don't want to use threads as I can imagine that will have its own issues with the input and output streams.
So is there a way for me to keep the process alive out of this function, or do I need to reorganise my code some other way? I believe having the process being called in main would work, but I really don't want to do that as I want to keep all the chess-related code in ChessGame.cpp.

Ok I believe that adding c.detach(); after initialising the boost.process child in startStockFish() has done what I want, as the program no longer terminates c when the function ends. Input appears to work fine with a detached process, simply writing output << cmd << std::endl; where cmd is the desired command as a std::string has no issues. However, output does have some issues, the usual method of
std::string line;
while (std::getline(input, line) && !line.empty())
{
// Do something with line
}
somewhat works, but std::getline(input, line) will get stuck in an infinite loop when there are no more lines to output. I couldn't find a direct solution to this, but I did find a work around.
Firstly I changed the initialisation of the boost.process child to
boost::process::child c(exec, args, boost::process::std_out > "console.txt", boost::process::std_in < output);
And then changed input to a std::ifstream, a file reader stream. Then to get the output I used
input.open("console.txt");
std::string line;
while (std::getline(input, line))
{
// Do something with line
}
input.close();
I also added remove("console.txt"); to the beginning of startStockFish() to attain a fresh text file.
I'm not confident that this is the best solution, as I am worried about what would happen if stockfish tried to write to console.txt as input was reading from it, but that hasn't seemed to occur or doesn't seemed to be an issue if it has occurred, so right now it is an adequate solution.

Related

Implementing File class for both read and write operations on the file

I need to implement a class which holds a regular text file that will be valid for both read and write operations from multiple threads (say, "reader" threads and "writers").
I am working on visual studio 2010 and can use only the available libraries that it (VS 2010) has, so I chose to use the std::fstream class for the file operations and the CreateThread function & CRITICAL_SECTION object from the header.
I might start by saying that I seek, at the beginning, for a simple solution - just so it works....:)
My idea is as follows:
I created a File class that will hold the file and a "mutex" (CRITICAL_SECTION object) as private members.
In addition, this class (File class) provides a "public interface" to the "reader/writer" threads in order to perform a synchronized access to the file for both read and write operations.
See the header file of File class:
class File {
private:
std::fstream iofile;
int size;
CRITICAL_SECTION critical;
public:
File(std::string fileName = " ");
~File();
int getSize();
// the public interface:
void read();
void write(std::string str);
};
Also see the source file:
#include "File.h"
File :: File(std::string fileName)
{
// create & open file for read write and append
// and write the first line of the file
iofile.open(fileName, std::fstream::in | std::fstream::out | std::fstream::app); // **1)**
if(!iofile.is_open()) {
std::cout << "fileName: " << fileName << " failed to open! " << std::endl;
}
// initialize class member variables
this->size = 0;
InitializeCriticalSection(&critical);
}
File :: ~File()
{
DeleteCriticalSection(&critical);
iofile.close(); // **2)**
}
void File :: read()
{
// lock "mutex" and move the file pointer to beginning of file
EnterCriticalSection(&critical);
iofile.seekg(0, std::ios::beg);
// read it line by line
while (iofile)
{
std::string str;
getline(iofile, str);
std::cout << str << std::endl;
}
// unlock mutex
LeaveCriticalSection(&critical);
// move the file pointer back to the beginning of file
iofile.seekg(0, std::ios::beg); // **3)**
}
void File :: write(std::string str)
{
// lock "mutex"
EnterCriticalSection(&critical);
// move the file pointer to the end of file
// and write the string str into the end of the file
iofile.seekg(0, std::ios::end); // **4)**
iofile << str;
// unlock mutex
LeaveCriticalSection(&critical);
}
So my questions are (see the numbers regarding the questions within the code):
1) Do I need to specify anything else for the read and write operations I wish to perform ?
2) Anything else I need to add in the destrutor?
3) What do I need to add here in order that EVERY read operation will occur necessarily from the beginning of the file ?
4) What do I need to modify/add here in order that each write will take place at the end of the file (meaning I wish to append the str string into the end of the file)?
5) Any further comments will be great: another way to implement , pros & cons regarding my implementation, points to watch out , etc'.....
Thanks allot in advance,
Guy.
You must handle exceptions (and errors in general).
No, you destructor even has superfluous things like closing the underlying fstream, which the object takes care of itself in its destructor.
If you always want to start reading at the beginning of the file, just open it for reading and you automatically are at the beginning. Otherwise, you could seek to the beginning and start reading from there.
You already opened the file with ios::app, which causes every write operation to append to the end (including that it ignores seek operations that set the write position, IIRC).
There is a bunch that isn't going to work like you want it to...
Most importantly, you need to define what you need the class to behave like, i.e. what the public interface is. This includes guarantees about the content of the file on disk. For example, after creating an object without passing a filename, what should it write to? Should that really be a file who's name is a single space? Further, what if a thread wants to write two buffers that each contain 100 chars? The only chance to not get interrupted is to first create a buffer combining the data, otherwise it could get interrupted by a different thread. It gets even more complicate concerning the guarantees that your class should fulfill while reading.
Why are you not using references when passing strings? Your tutorial should mention them.
You are invoking the code to enter and leave the critical section at the beginning and end of a function scope. This operation should be bound to the ctor and dtor of a class, check out the RAII idiom in C++.
When you are using a mutex, you should document what it is supposed to protect. In this case, I guess it's the iofile, right? You are accessing it outside the mutex-protected boundaries though...
What is getSize() supposed to do? What would a negative size indicate? In case you want to signal errors with that, that's what exceptions are for! Also, after opening an existing, possibly non-empty file, the size is zero, which sounds weird to me.
read() doesn't return any data, what is it supposed to do?
Using a while-loop to read something always has to have the form "while try-to-read { use data}", yours has the form "while success { try-to-read; use data; }", i.e. it will use data after failing to read it.
Streams have a state, and that state is sticky. Once the failbit is set, it remains set until you explicitly call clear().
BTW: This looks like logging code or a file-backed message queue. Both can be created in a thread-friendly way, but in order to make suggestions, you would have to tell us what you are actually trying to do. This is also what you should put into a comment section on top of your class, so that any reader can understand the intention (and, more important now, so that YOU make up you mind what it's supposed to be).

c++ ofstream pointer fails to write to disk

I am having trouble writing to ofstream pointer and this is quite perplexing as I really don't see anything that is missing anymore. Note, this is a follow up from this question:
C++ vector of ofstream, how to write to one particular element
My code is as follows:
std::vector<shared_ptr<ofstream>> filelist;
void main()
{
for(int ii=0;ii<10;ii++)
{
string filename = "/dev/shm/table_"+int2string(ii)+".csv";
filelist.push_back(make_shared<ofstream>(filename.c_str()));
}
*filelist[5]<<"some string"<<endl;
filelist[5]->flush();
exit(1);
}
This does doesn't write anything to the output file but it does create 10 empty files. Does anybody know what might possibly be wrong here?
EDIT: I ran some further tests. I let the code run without exit(1) until completion, over all files until all callbacks are finished. It turns out that some files are not empty, while others that should have data are empty.
There is plenty of disk space, and I know I have more file descriptors than are necessary for this. Any explanation for why some of the files would be written properly while others are not?
I'd try: (*filelist[5])<<"some string\n";.
I'd guess, however, that you probably meant to write to the files inside a loop -- as-is, you're writing to only one file.
Oh, and in C++, you don't want to use exit.
Edit: Here's a quick (tested) standalone demo:
#include <fstream>
#include <string>
#include <vector>
std::vector<std::ofstream *> filelist;
int main() {
for(int ii=0;ii<3;ii++)
{
char *names[] = {"one", "two", "three"};
std::string filename = "c:\\trash_";
filename += names[ii];
filename += ".txt";
filelist.push_back(new std::ofstream(filename.c_str()));
}
for (int i=0; i<filelist.size(); i++) {
(*filelist[i])<<"some string\n";
filelist[i]->close();
}
}
Note, however, that the file name this generates is for Windows, whereas the original was (apparently) intended for something Unix-like. For a Unix-like OS, you'll need/want a different file name string.
Try closing the file before you call exit with filelist[5]->close();. You've aborted a process with an open file which means your write may not have made it to the OS buffer or was discarded upon process exit. You could also remove the exit call it would probably fix the problem. The results of IO on a process that is aborted are tricky to nail down, so it's best to try avoiding aborts with active IO or to assume any active IO will fail upon abort.

Capture the output of a process in multi-threaded c++

My requirements are simple: start a process, wait for it to finish, then capture and process it's output.
For the longest time I've been using the following:
struct line : public std∷string {
friend std∷istream& operator>> (std∷istream &is, line &l) {
return std∷getline(is, l);
}
};
void capture(std::vector<std::string> &output, const char *command)
{
output.clear();
FILE *f = popen(command, "r");
if(f) {
__gnu_cxx::stdio_filebuf<char> fb(f, ios∷in) ;
std::istream fs(&fb);
std::istream_iterator<line> start(fs), end;
output.insert(output.end(), start, end);
pclose(f);
}
}
And it works really well on single threaded programs.
However, if I call this function from inside a thread, sometimes the popen() call hangs and never return.
So, as a proof-of-concept I replaced the function for this ugly hack:
void capture(std::vector<std::string> &output, const char *command)
{
output.clear();
std::string c = std::string(command) + " > /tmp/out.txt";
::system(c.c_str());
ifstream fs("/tmp/out.txt", std::ios::in);
output.insert(output.end(), istream_iterator<line>(fs), istream_iterator<line>());
unlink("/tmp/out.txt");
}
It's ugly but works, however it kept me wondering what would be the proper way to capture a process output on a multi-threaded program.
The program runs on linux in a embedded powerquiccII processor.
See this: popen - locks or not thread safe? and other references do not seem conclusive that popen() needs to be thread-safe, so perhaps since you are using a less-popular platform, your implementation is not. Any chance you can view the source code of the implementation for your platform?
Otherwise, consider creating a new process and waiting upon it. Or hey, stick with the silly system() hack, but do handle its return code!

close an unopened stream

I have ifstream and an ofstream that in runtime might be opened or not (depends on what the user enters in command line. i declare the variables anyway, and i have a method that opens the stream if needed.
my problem is at the end of the program i don't know if i need to close them or not.
Is there anyway in c++ to know if a stream was opened? Like in Java you can give a stream the null value and then ask if its null (it means that it was never opened)..
Is it ok to close a stream that was never opened?
this is the code:
int main(int argc, char* argv[]) {
static std::ifstream ifs;
static std::ofstream ofs;
//might or might not open the streams:
OpenStreams(ifs,ofs,argc-1,argv);
........
//here i would like to close the streams at the end of the program
//or not (if they were not opened
return 0;
}
Thanks!
I don't really know, nor care to look. Just leave it to the destructors, the standard file streams will close the files during destruction if needed.
EDIT: On lifetimes of objects and guaranteed destruction...
To follow up the second comment to Ben Voigt that I wrote, this is a small test on object lifetimes:
#include <cstdlib>
#include <iostream>
#include <string>
struct test {
std::string name;
test( std::string const & name ) : name(name) {
std::cout << "test " << name << std::endl;
}
~test() { std::cout << "~test " << name << std::endl; }
};
void foo( bool exit ) {
test t1( "1" );
static test t2( "2" );
test t3( "3" );
if ( exit ) {
std::exit(1);
}
}
int main()
{
foo(false);
std::cout << std::endl;
foo(true);
}
And the result of the execution:
test 1
test 2
test 3
~test 3
~test 1
test 1
test 3
~test 2
It can be seen that during the first execution the construction of the objects in foo occurs in the same order as the code., but when the function exits only the objects with auto storage get destroyed, with the object with static storage outliving the function execution.
In the second call to foo, the auto objects get recreated, while the static object doesn't, as expected, since it was created in a previous call. Because foo calls exit() in the second call, the auto objects in foo don't get destructed. On the other hand, the static object is correctly destructed.
Why not just test this using is_open() before you issue the close()?
No close call needed - the streams close itself when they are open when they are destroyed. Also, the static there looks suspicious. main is called only once, so it doesn't have any effect here (apart from pedantic standardese differences that don't matter here, i think.... Definitely not in the case shown).
That said, you can just call close if a stream is not opened - close will return a null pointer if it wasn't open. (I was looking at the spec for basic_filebuf<>::close - the file streams's close returns void).
File-streams can also handle non-open streams: If the stream wasn't open, it sets the failbit. You can check for that using fail() (which tests whehter the failbit or badbit is set). But there is is_open anyway to test whether the stream is open, but you don't need it for the above reasons.
Just don't make the variables static, that way they automatically close when main() returns.
You can use the is_open method to test if a stream has been opened, then close it.
Why not set a flag before opening a stream. Check the flag again if you need to close the stream object if any.
Better would be to pass that open stream object to the flag while opening a stream & use it to close the stream. If the flag has not been initialized or is null don't close.

How to call an external program with parameters?

I would like to call a windows program within my code with parameters determined within the code itself.
I'm not looking to call an outside function or method, but an actual .exe or batch/script file within the WinXP environment.
C or C++ would be the preferred language but if this is more easily done in any other language let me know (ASM, C#, Python, etc).
When you call CreateProcess(), System(), etc., make sure you double quote your file name strings (including the command program filename) in case your file name(s) and/or the fully qualified path have spaces otherwise the parts of the file name path will be parsed by the command interpreter as separate arguments.
system("\"d:some path\\program.exe\" \"d:\\other path\\file name.ext\"");
For Windows it is recommended to use CreateProcess(). It has messier setup but you have more control on how the processes is launched (as described by Greg Hewgill). For quick and dirty you can also use WinExec().
(system() is portable to UNIX).
When launching batch files you may need to launch with cmd.exe (or command.com).
WinExec("cmd \"d:some path\\program.bat\" \"d:\\other path\\file name.ext\"",SW_SHOW_MINIMIZED);
(or SW_SHOW_NORMAL if you want the command window displayed ).
Windows should find command.com or cmd.exe in the system PATH so in shouldn't need to be fully qualified, but if you want to be certain you can compose the fully qualified filename using CSIDL_SYSTEM (don't simply use C:\Windows\system32\cmd.exe).
C++ example:
char temp[512];
sprintf(temp, "command -%s -%s", parameter1, parameter2);
system((char *)temp);
C# example:
private static void RunCommandExample()
{
// Don't forget using System.Diagnostics
Process myProcess = new Process();
try
{
myProcess.StartInfo.FileName = "executabletorun.exe";
//Do not receive an event when the process exits.
myProcess.EnableRaisingEvents = false;
// Parameters
myProcess.StartInfo.Arguments = "/user testuser /otherparam ok";
// Modify the following to hide / show the window
myProcess.StartInfo.CreateNoWindow = false;
myProcess.StartInfo.UseShellExecute = true;
myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
myProcess.Start();
}
catch (Exception e)
{
// Handle error here
}
}
I think you are looking for the CreateProcess function in the Windows API. There are actually a family of related calls but this will get you started. It is quite easy.
One of the simplest ways to do this is to use the system() runtime library function. It takes a single string as a parameter (many fewer parameters than CreateProcess!) and executes it as if it were typed on the command line. system() also automatically waits for the process to finish before it returns.
There are also limitations:
you have less control over the stdin and stdout of the launched process
you cannot do anything else while the other process is running (such as deciding to kill it)
you cannot get a handle to the other process in order to query it in any way
The runtime library also provides a family of exec* functions (execl, execlp, execle, execv, execvp, more or less) which are derived from Unix heritage and offer more control over the process.
At the lowest level, on Win32 all processes are launched by the CreateProcess function, which gives you the most flexibility.
simple c++ example (found after searching a few websites)
#include <bits/stdc++.h>
#include <cassert>
#include <exception>
#include <iostream>
int main (const int argc, const char **argv) {
try {
assert (argc == 2);
const std::string filename = (const std::string) argv [1];
const std::string begin = "g++-7 " + filename;
const std::string end = " -Wall -Werror -Wfatal-errors -O3 -std=c++14 -o a.elf -L/usr/lib/x86_64-linux-gnu";
const std::string command = begin + end;
std::cout << "Compiling file using " << command << '\n';
assert (std::system ((const char *) command.c_str ()) == 0);
std::cout << "Running file a.elf" << '\n';
assert (std::system ((const char *) "./a.elf") == 0);
return 0; }
catch (std::exception const& e) { std::cerr << e.what () << '\n'; std::terminate (); }
catch (...) { std::cerr << "Found an unknown exception." << '\n'; std::terminate (); } }