I need a program to communicate with a subprocess that is relying on in- and
output. The problem is that I am apparently not able to use QProcess correctly.
The code further down should create a QProcess, start it and enter the main while loop. In there it prints all the output created by the subprocess to the console and subsequently asks the user for input which is then passed to the subprocess via write(...).
Originally I had two problems emerging from this scenario:
The printf's of the subprocess could not be read by the parent process.
scanf in the subprocess is not receiving the strings sent via write.
As for (1), I came to realize that this is a problem caused by the buffering of the subprocess' stdout. This problem can be solved easily with fflush(stdout) calls or manipulations regarding its flushing behavior.
The second problem is the one I can't wrap my head around. write gets called and even returns the correct number of sent bytes. The subprocess, however, is not continuing its excecution, because no new data is written to its output. The scanf seems not to be receiving the data sent. The output given by the program is:
Subprocess should have started.
124 bytes available!
Attempting to read:
Read: This is a simple demo application.
Read: It solely reads stdin and echoes its contents.
Read: Input exit to terminate.
Read: ---------
Awaiting user input: test
Written 5 bytes
No line to be read...
Awaiting user input:
I am seriously stuck right here. Google + heavy thinking having failed on me, I want to pass this on to you as my last beacon of hope. In case I am just failing to see the forest for all the trees, my apologies.
In case this information is necessary: I am working on 64bit MacOS X using Qt5 and the clang compiler. The subprocess-code is compiled with gcc on the same machine.
Thank you very much in advance,
NR
Main-Code:
int main() {
// Command to execute the subprocess
QString program = "./demo";
QProcess sub;
sub.start(program, QProcess::Unbuffered | QProcess::ReadWrite);
// Check, whether the subprocess is starting correctly.
if (!sub.waitForStarted()) {
std::cout << "Subprocess could not be started!" << std::endl;
sub.close();
return 99;
}
std::cout << "Subprocess should have started." << std::endl;
// Check, if the subprocess has written its starting message to the output.
if (!sub.waitForReadyRead()) {
std::cout << "No data available for reading. An error must have occurred." << std::endl;
sub.close();
return 99;
}
while (1) {
// Try to read the subprocess' output
if (!sub.canReadLine()) {
std::cout << "No line to be read..." << std::endl;
} else {
std::cout << sub.bytesAvailable() << " bytes available!" << std::endl;
std::cout << "Attempting to read..." << std::endl;
while (sub.canReadLine()) {
QByteArray output = sub.readLine();
std::cout << "Read: " << output.data();
}
}
std::cout << "Awaiting user input: ";
std::string input;
getline(std::cin, input);
if (input.compare("exit") == 0) break;
qint64 a = sub.write(input.c_str());
qint64 b = sub.write("\n");
sub.waitForBytesWritten();
std::cout << "Written " << a + b << " bytes" << std::endl;
}
std::cout << "Terminating..." << std::endl;
sub.close();
}
Subprocess-Code:
int main() {
printf("This is a simple demo application.\n");
printf("It reads stdin and echoes its contents.\n");
printf("Input \"exit\" to terminate.\n");
while (1) {
char str[256];
printf("Input: ");
fflush(stdout);
scanf("%s", str);
if (strcmp(str, "exit") == 0) return 0;
printf("> %s\n", str);
}
}
P.s: Since this is my first question on SO, please tell me if something is wrong concerning the asking style.
Solution
After many many more trials & errors, I managed to come up with a solution to the problem. Adding a call to waitForReadyRead() causes the main process to wait until new output is written by the subprocess. The working code is:
...
sub.waitForBytesWritten();
std::cout << "Written " << a + b << " bytes" << std::endl;
// Wait for new output
sub.waitForReadyRead();
...
I still don't have a clue why it works this way. I guess it somehow relates to the blocking of the main process by getline() vs blocking by waitForReadyRead(). To me it appears as if getline() blocks everything, including the subprocess, causing the scanf call never to be processed due to race conditions.
It would be great, if someone who understands could drop an explanation.
Thank you for your help :)
NR
This will not work. You are waiting for the sent bytes to be written but you are not waiting for the echo. Instead you are entering the getline() function waiting for new user input. Keep in mind that two processes are involved here where each process can be delayed to any degree.
Apart from this you should consider building your Qt application asynchronously (having an event loop) instead of trying the synchronous approach. This way your Qt application can do things in parallel... e.g. reading input or waiting for input from the remote process while still not being blocked and able to accept user input.
Related
#include <bits/stdc++.h>
using namespace std;
void scan_a_line_indefinitely()
{
// scan line indefinitely
string input_line;
while(getline(cin,input_line))
{
cout << input_line ; **// doesn't print if i use this line**
//cout << input_line << endl; **// if i use this line, it works fine**
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
scan_a_line_indefinitely();
return 0;
}
someone please help me understand the problem with this code.
i think the problem is with cout.tie() and cout.tie(), when i remove these, program works fine.
std::cout will flush under these conditions:
An input-stream which is tied to std::cout tries to read input.
You removed the ties.
iostreams are synchronized with stdio, thus effectively unbuffered.
You disabled the synchronization.
The buffer is full.
That takes a bit longer.
The program ends normally.
That comes too late for you.
There is a manual flush (stream.flush() which is called when streaming std::flush; stream << std::endl is equivalent to stream << stream.widen('\n') << std::flush).
You have none of those.
So, fix any of them and you will see your output earlier.
If only iostreams are used you can add a manual flush to the output :
std::cout.flush();
Or
std::cout << /* the output */<< std::flush;
Also:
std::cout << std::endl is equivalent to std::cout << '\n' << std::flush
This is my simplified class which is used to detect problem in my full program:
SimpleThread.h
class SimpleThread {
public:
SimpleThread();
~SimpleThread();
void startThread();
void threadFn();
private:
SerialPort mySerial;
std::thread myThread;
int count;
std::mutex myMutex;
};
SimpleThread.cpp
SimpleThread::SimpleThread(): mySerial("/dev/ttyACM0") {
count = 0;
mySerial.Open(//Here correct params//);
}
SimpleThread::~SimpleThread() {}
void SimpleThread::threadFn() {
char cp;
while (true) {
cp = mySerial.ReadByte(0);
std::cout << count++ << " " << cp << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void SimpleThread::startThread() {
myThread = std::thread(&SimpleThread::threadFn, this);
myThread.detach();
}
main.cpp
int main() {
SimpleThread thr;
thr.startThread();
while (true) {
std::cout << "Waiting 5 seconds" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
}
}
The main idea of my example: I am using class member function as thread function to read data from opened serial port. There are no problems in using this class without reading from serial: main loop prints message every 5 seconds while thread loop (function inside class) prints 5 numbers.
Now I want to implement reading from serial port while my main loop is going to do something else. To read/write in serial I took this not so up-to-date serial library.
In this case class starts to work unexpected for me: main loop (which should show message every 5 seconds) shows its message faster then thread loop (about 40 times while 1 second). This code works wrong cause main loop prints message 40 times at 1 second (after read byte) despite sleep function.
So my question is: where is the root of my problem? Should I use another serial library or there are some features connected with interruptions which I dont know about?
Edit: If I use next loop for reading with checking if data is available, the main loop prints after every read byte. Looks like reading byte in thread loop interrupts main loop and cancels sleeping.
if ( mySerial.IsDataAvailable() ) {
cp = mySerial.ReadByte(0);
std::cout << count++ << " " << cp << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
Edit 2: Moreover, I tested just opening the Serial but without reading from Serial in loop (with changed pause in thread loop on two seconds)
if ( mySerial.IsDataAvailable() ) {
std::cout << count++ << " " << cp << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
}
In this case main loop prints every one second. There is no problem only if Serial port is not opened.
libserial uses asynchronous I/O which is based on signals (SIGIO to be precise) and there was a bug in GCC 5 (#66803) in which std::this_thread::sleep_for was interrupted by signals. It has been fixed in GCC 6.
The possible solutions are:
Upgrade your compiler to GCC 6+ or clang/LLVM.
Use a workaround like the one mentioned in the bug 66803 or try sleep_until:
auto wakeup_time = std::chrono::steady_clock::now() + std::chrono::seconds(1);
std::this_thread::sleep_until(wakeup_time);
Use blocking I/O (I believe you can simply open the serial device as a file and read from it).
I have a program that I am writing for an embedded device, and I am trying to use pipes to pass messages. Before I get to passing messages between my program and another, I was building test code to ensure that everything is working properly, and encountered a problem. Note that the embedded device doesn't support c++11 (hence the use of pthread's).
The code in question:
void* testSender(void *ptr) {
std::cout << "Beginning testSender" << std::endl;
int pipe = open("/dev/rtp10", O_WRONLY);
if (pipe < 0) {
std::cout << "write pipe failed to open" << std::endl;
} else {
std::cout << "write pipe successfully opened" << std::endl;
}
std::cout << "Ending testSender" << std::endl;
return NULL;
}
void* testReceiver(void *ptr) {
std::cout << "Beginning testReceiver" << std::endl;
int pipe = open("/dev/rtp10", O_RDONLY);
if (pipe < 0) {
std::cout << "read pipe failed to open" << std::endl;
} else {
std::cout << "read pipe successfully opened" << std::endl;
}
std::cout << "Ending testReceiver" << std::endl;
return NULL;
}
void testOpenClosePipes() {
std::cout << "Beginning send/receive test" << std::endl;
pthread_t sendThread, receiveThread;
pthread_create(&sendThread, NULL, &testSender, NULL);
pthread_create(&receiveThread, NULL, &testReceiver, NULL);
std::cout << "waiting for send and receive test" << std::endl;
pthread_join(receiveThread, NULL);
pthread_join(sendThread, NULL);
std::cout << "Done testing open send/receive" << std::endl;
}
The function testOpenClosePipes() is called from my main thread and after calling it I get the following output:
Beginning send/receive test
waiting for send and receive test
Beginning testReceiver
Beginning testSender
write pipe failed to open
Ending testSender
and then the program hangs. I believe that this is because the read pipe has been opened and is then waiting for a sender to connect to the pipe, but I could be wrong there. Note that if I start the receive thread before I start the send thread, then the result is as follows:
Beginning send/receive test
waiting for send and receive test
Beginning testSender
Beginning testReceiver
read pipe failed to open
Ending testReceiver
From what I have read about pipes so far, what appears to be occurring is that one of the two (either send or receive) is opening correctly, and then holding until the other end of the pipe has been opened. However, the other end of the pipe is failing to open correctly, which ends up leaving the system hanging because the open pipe is waiting for its connection before it successfully moves on. I am unable to figure out why this is happening however, and am looking to get help with that.
After reviewing my problem, it appears that the problem isn't actually in the use of the pipes in question, it is that /dev/rtp* opens a pipe for the embedded system's special application, and is not actually a pipe that can go from linux to linux. This is solved by using a different pipe and first creating said pipe with the mkfifo command prior to attempting to open a pipe.
How about checking the errno value for the failed open call?
I'm dealing with fscanf function in C++ and I've confused point about fscanf. Why it doesn't block the calling thread while the stream is absolutely empty.
In my expectation, the main thread should be blocked on the fscanf function, it will be released after 3 seconds because the file stream is going to be written to after 3 seconds by the child thread.
But reality, it doesn't seem like I expected. Please somebody tells me why?
The following is my lines of code:
#include <windows.h>
#include <iostream>
#include <stdio.h>
DWORD WINAPI subroutine(LPVOID data)
{
FILE* file = (FILE*)data;
std::cout << "I'll send you something after 3s" << std::endl;
Sleep(3000);
if (file != NULL)
{
std::cout << "I'm writing now" << std::endl;
char* sentence = "Hello";
fputs(sentence, file);
}
}
int main()
{
FILE* file = tmpfile();
if ( file != NULL )
{
CreateThread(NULL, 0, subroutine, file, 0, NULL);
char something[50];
std::cout << "Blocking..." << std::endl;
rewind(file);
fscanf(file, "%s", something);
std::cout << "Message is " << something << std::endl;
}
std::cout << "Done" << std::endl;
if (file != NULL)
{
fclose(file);
}
return 0;
}
============
Because people may don't understand why I think fscanf should block the calling thread.
This is why I have the above question.
int main()
{
char something[50];
fscanf(stdin, "%s", something);
std::cout << something << std::endl;
return 0;
}
The program stopped to you enter something.
You are using a regular file, so when you are at its end fscanf returns EOF. The fact that there's another thread that in a few seconds will append some data is irrelevant, and the C library has no way to know it anyway.
Standard input blocks because when it is attached to a console it doesn't end (until the user presses Ctrl-D), so if you ask for more input and it's not ready to take it just waits (think to it as if it was a file on a disk extremely slow to provide the data).
Besides, using a FILE * backed by an actual file for cross-thread communication seems like a bad idea; besides the efficiency concerns and the headaches relative the thread-safety of sharing a FILE * between two threads, it maps badly to the problem at hand; what you seem to want here is a FIFO-like communication channel between two threads, not a storage device for data.
If you want to have FIFO communication between the two threads you can use - for example - an anonymous pipe or just a thread-safe message queue.
In two different process, there is a semaphore initialized in a shared memory. In one of the processes, it is being continuously posted. Here is a part of the second process code:
sem_init(&(memoryUpper.data()->write), 1, 1);
while(threadIsRunning)
{
std::cerr << __FILE__ << " :: " << __LINE__ << std::endl;
sem_wait(&(memoryUpper.data()->write));
std::cerr << __FILE__ << " :: " << __LINE__ << std::endl;
}
However, the second process doesn't pass sem_wait more than once.
Testing the same code in a more clean process without thread makes it work. Also turning sem_wait(...) to while(sem_trywait(...)) fixes the problem. On the other hand a SIGINT prints the outputs that was intended to be printed before interrupting.
P.S.: It shouldn't be a problem of cout buffer as I have already tested it with a handmade segmentation fault after waiting for the 10th time and it works just as before.