This question already has answers here:
How to make reading from `std::cin` timeout after a particular amount of time
(5 answers)
Closed 4 years ago.
In C++ on OSX, how do we check std::cin for data without waiting?
The expected data is not coming from a keyboard or human, but from a program that has started my executable and talks to my executable via stdin. This 'parent' program will tell me to start a long process, may interrupt, and I may periodically send data back to it via stdout, therefore the checking of stdin must not block. I'm using XCode.
So far I have attempted to test via the following, neither of which seem to work:
//Return true if there is data waiting version 1
return (std::cin.peek() != EOF);
//Return true if there is data waiting version 2
return (std::cin.rdbuf() && std::cin.rdbuf()->in_avail() >= 0);
To fill out the idea mentioned in a comment, the easiest way since C++11 is simply to start a thread that waits for input and, when it is received, add it to a shared queue container. Doing so requires use of mutex locking & unlocking. This container then can be used to check if empty and, if it has something in it, the data can just be read and popped off of the front of the queue. Something like the following:
#include <thread>
#include <string>
#include <iostream>
std::mutex qmutex;
std::queue<std::string> queue;
void listen() {
std::string sin;
while (true) {
std::cin >> sin; // Thread will wait here for stdin to arrive
qmutex.lock();
queue.push(sin);
qmutex.unlock();
}
}
void mainstuff() {
std::thread t1(listen);
while (true) {
qmutex.lock();
if (!queue.empty()) {
//There's something in the queue, read it/take a copy
queue.pop();
}
qmutex.unlock();
// Respond to input
// Continue work
}
}
I don't believe cin supports non-blocking I/O operations or timeouts.
Here's an example of the lower-level way to accomplish the task, using select() and file descriptors. This program will immediately print to stdout any text it receives from stdin, and also wake up every 5 seconds (even if no text is received from stdin) just to print a fixed message. You can modify the wakeup timeout to whatever you like (including zero for an instantaneous-poll behavior), and/or add more file descriptors for it to react to if you prefer a more event-driven approach.
#include <stdio.h>
#include <sys/select.h>
static void RegisterFileDescriptor(int fd, int & maxFD, fd_set & fdset)
{
FD_SET(fd, &fdset);
if (fd > maxFD) maxFD = fd;
}
int main()
{
const int stdinFileno = fileno(stdin);
// This call is just here so that our parent process will immediately see any
// text lines that we print to stdout. If you're only reading from stdin and never
// writing responses back to stdout, then it's not really necessary.
(void) setlinebuf(stdout);
fd_set readSet;
while(true)
{
int maxFD = -1;
FD_ZERO(&readSet);
RegisterFileDescriptor(stdinFileno, maxFD, readSet);
// If you want to react to incoming data on any other
// file descriptors as well, you could call
// RegisterFileDescriptor on them here
struct timeval timeoutDelay = {5, 0}; // let's force a wakeup every 5 seconds
if (select(maxFD+1, &readSet, NULL, NULL, &timeoutDelay) < 0)
{
perror("select");
break;
}
printf("select() returned!\n");
if (FD_ISSET(stdinFileno, &readSet))
{
char buf[512];
if (fgets(buf, sizeof(buf), stdin)) printf("Read from stdin: [%s]\n", buf);
}
}
return 0;
}
Related
I'm trying to multiplex an unnamed pipe with some other file descriptors.
The problem is that the pipe file descriptor always appears in the result of select. In other words the event-loop reads from pipe for infinite times. Here is a metaphor of what I want to do, and what actually happens.
#include <iostream>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
int main(){
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
int fdmax; // maximum file descriptor number
int pfd[2];
if(pipe(pfd)!=0) {cout<<"Unable to create a pipe.\n",exit(1);};
FD_SET(0, &master);
FD_SET(pfd[0],&master);
fdmax=pfd[0];
if(fork()){//Parent
for (;;){
read_fds = master; // copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
for(int i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) {
int n;
char buff[200];
if (i==pfd[0]){
close(pfd[1]);
n=read(pfd[0],buff,sizeof(buff));
buff[n]=0;
cout<<"Read from pipe:"<<buff<<endl;
}else if(i==0){
n=read(0,buff,sizeof(buff));
buff[n]=0;
cout<<"Read from std:"<<buff<<endl;
}
}
}
}
}else{//Child
usleep(50000);
char buff[200]="This is a simple sample.";
close(pfd[0]);
write(pfd[1],buff,sizeof(buff));
close(pfd[1]);
exit(0);
}
}
First of all, the read() call can read less than number of bytes specified in the last argument ant id does not automatically append zero-byte terminator, so your receiving code can easily access uninitialized memory in buff[] and after it (if there is no zero byte). You need to check return value when calling read and use only so many bytes from buffer.
Then, the select call returns when any file descriptor in the readfds set won't block on subsequent read. Which includes end-of-file condition. This likely happens in your case, when the forked process closes its fd. See this SO question too.
Could it be the reason for the problem you encounter? Checking return value when calling read make this clear to you, as read returns zero if-and-only-if the fd reached end of file.
Last detail – it does not make much sense to close pfd[1] only after pfd[0] is returned in the readfds. You should close it immediately after the fork, so it remains open in the child process only if you have no use for it in the parent process.
I am currently trying to write a program that will read Bluetooth output from an Arduino HC-05 module on a Serial Communications Port.
http://cdn.makezine.com/uploads/2014/03/hc_hc-05-user-instructions-bluetooth.pdf
When I open a Putty terminal and tell it to listen to COM4, I am able to see the output that the program running on the Arduino is printing.
However, when I run the following program to try to process incoming data on the serial port programatically, I get the output shown.
#include <Windows.h>
#include <string>
#include <atltrace.h>
#include <iostream>
int main(int argc, char** argv[]) {
HANDLE hComm = CreateFile(
L"COM4",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
NULL,
0
);
if (hComm == INVALID_HANDLE_VALUE) {
std::cout << "Error opening COM4" << std::endl;
return 1;
}
DWORD dwRead;
BOOL fWaitingOnRead = false;
OVERLAPPED osReader = { 0 };
char message[100];
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osReader.hEvent == NULL) {
std::cout << "Error creating overlapping event" << std::endl;
return 2;
}
while (1) {
if (!fWaitingOnRead) {
if (!ReadFile(
hComm,
&message,
sizeof(message),
&dwRead,
NULL
)) {
if (GetLastError() != ERROR_IO_PENDING) {
std::cout << "Communications error" << std::endl;
return 3;
}
}
else {
message[100] = '\0';
std::cout << message << std::endl;
}
}
}
return 0;
}
I have made changes to the handle and the ReadFile function call so that it will be making the calls synchronously in an infinite loop. However, Visual Studio pops up a warning saying that the program has stopped working then asks to debug or close program. My assumption is that it must be stalling somewhere or failing to execute some WindowsAPI function somewhere up the stack.
Any help, pointers, greatly appreciated.
At least IMO, using overlapped I/O for this job is pretty severe overkill. You could make it work, but it would take a lot of extra effort on your part, and probably accomplish very little.
The big thing with using comm ports under Windows is to set the timeouts to at least halfway meaningful values. When I first did this, I started by setting all of the values to 1, with the expectation that this would sort of work, but probably consume excessive CPU time, so I'd want to experiment with higher values to retain fast enough response, while reducing CPU usage.
So, I wrote some code that just set all the values in the COMMTIMEOUTS structure to 1, and setup the comm port to send/read data.
I've never gotten around to experimenting with longer timeouts to try to reduce CPU usage, because even on the machine I was using when I first wrote this (probably a Pentium II, or thereabouts), it was functional, and consumed too little CPU time to care about--I couldn't really see the difference between the machine completely idle, and this transferring data. There might be circumstances that would justify more work, but at least for any need I've had, it seems to be adequate as it is.
That's because message has the wrong type.
To contain a string, it should be an array of characters, not an array of pointers to characters.
Additionally, to treat it as a string, you need to set the array element after the last character to '\0'. ReadFile will put the number of characters it reads into dwRead.
Also, it appears that you are not using overlapped I/O correctly. This simple program has no need for overlapped I/O - remove it. (As pointed out by #EJP, you are checking for ERROR_IO_PENDING incorrectly. Remove that too.)
See comments below, in your program:
if (!fWaitingOnRead) {
if (!ReadFile( // here you make a non-blocking read.
hComm,
message,
sizeof(*message),
&dwRead,
&osReader
)) {
// Windows reports you should wait for input.
//
if (GetLastError() != ERROR_IO_PENDING) {
std::cout << "Communications error" << std::endl;
return 3;
}
else { // <-- remove this.
// insert call to GetOverlappedcResult here.
std::cout << message << std::endl;
}
}
}
return 0; // instead of waiting for input, you exit.
}
After you call ReadFile() you have to insert a call for GetOverlappedResult(hComm, &osReader, &dwBytesRceived, TRUE) to wait for the read operation to complete and have some bytes in your buffer.
You will also need to have a loop in your program if you don't want to exit prematurely.
If you do not want to do overlapped i/o (which is a wise decision) , do not pass an OVERLAPPED pointer to ReadFile. ReadFile will block until it has some data to give you. You will then obviously not need to call GetOverlappedresult()
For the serial port, you also need to fill in a DCB structure. https://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx
You can use BuildCommDCB()to initialize it. There is a link to it in the MS doc, CallGetCommState(hComm, &dcb) to initialize the serial port hardware. The serial port needs to know which baud rate etc. you need for your app.
So, i am trying to make a c++ WinSock2 chatter, just for learning.
It is a console application and i want to take user input (for sending to the counterpart), but i still want to be able to recive. (so you can write a message while still being able to recive one)...
When using cin >> input; the program "pauses" until the user has enterd something, that way it is "turn based" (one user writes something and sends it, then the other user writes something and sends it).
Is there a way to make the user be able to write something WHILE the recive stuff is still running? (Preferably something else than multi threading)
What about checking if buffer isn't empty? But code wouldn't be really portable then, because you need to make some system calls as I know. See this.
But maybe you can do it with some C code, I'll do some research and update my answer.
UPD: Ok, I did it. What you need is select function.
It could wait till stdin is ready for read, and that's what we need.
But looks like it don't work with C++ streams, so you need to use only C code for reading.
Let's jump to definition:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout)
Ok, we need to check only read buffer, so writefds and errorfds could be NULL. And we need to check only stdin, so nfds is 1 (number of fdses)
What about timeout? It's should be 0, so we need to initialize variable struct timeval timeout and set seconds and nanoseconds to 0 by timeout.tv_sec = 0 and timeout.tv_usec = 0.
So, only readfds left. It's pretty simple too: we need to initialize variable, "zero" it, and add stdin.
It can be done with fd_set readfds, FD_ZERO(&readfds) and FD_SET(STDIN_FILENO, &readfds).
Okay, final step: function call. It should be select(1, &readfds, NULL, NULL, &timeout).
This would return 0 if input buffer is empty and 1 if it's not.
UPD2: Looks like it's not C++ streams, something strange happens and it breaks when buffer is empty at very first call. I'll try to catch the problem.
UPD3: Ok, Now I figured it out. Looks like you can use select with C++ streams.
Select has VERY strange (IMHO) feature: it resets readfds. I'm not sure how to prevent It from doing this, so I just used one more fd_set variable to hold it, so you need to add fd_set savefds = readfds after readfds initialization, and readfds = savefds after each call. That's awful solution, but I don't know how could I improve it.
So code is:
Initialization:
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
fd_set savefds = readfds;
Timeout initialization:
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
And usage:
if (select(1, &readfds, NULL, NULL, &timeout)) {
cin >> input;
send(input);
}
readfds = savefds;
UPD4: Don't forget to include unistd.h and cstdlib
The above answer is quite helpful.
Here is an example (base code taken from SELECT man page):
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
int main(void)
{
fd_set rfds, save_rfds;
struct timeval tv;
int retval;
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Make a copy of rfds, as after running select, it gets reset */
save_rfds = rfds;
/* Wait for zero seconds. */
tv.tv_sec = 0;
tv.tv_usec = 0;
while(true){
retval = select(1, &rfds, NULL, NULL, &tv);
rfds = save_rfds;
if (retval == -1)
perror("select()");
else if (retval){
/* Runs as soon as you enter a value and press enter. */
std::cout<<"Data is available now.\n";
std::string s;
getline(std::cin, s);
std::cout<<"Data Input: "<<s<<"\n";
/* FD_ISSET(0, &rfds) will be true. */
}
}
exit(EXIT_SUCCESS);
}
Before the below code I do:
create 1 pipe to read output from forked process
fork()
execv() a python script
Then in the parent process I do:
//set pipes to non-Blocking
File * cout_f = fdopen(cout_pipe[0], "r");
int flags = fcntl(cout_pipe[0], F_GETFL, 0);
fcntl(cout_pipe[0], F_SETFL, flags|O_NONBLOCK);
// read from pipe and send it up through a callback method
int stat;
size_t size = 0;
char buffer [ 1000 ];
do
{
while((size = fread(buffer, sizeof(char), sizeof(char)*1000, cout_f))!=0)
{
call_back_function(buffer, size);
}
}while(waitpid(child_pid, &stat, WNOHANG) != -1)
//Do 1 extra read
while((size = fread(buffer, sizeof(char), sizeof(char)*1000, cout_f))!=0)
{
call_back_function(buffer, size);
}
The problem I am facing happens when the child process prints to stdout and exits (normally) before flushing. I miss what was sent in the pipe.
Here are my questions:
Is the above code safe/correct or can it be improved?
Is there a way to read the entire pipe at the last moment when the subprocess dies, even if it doesn't flush its stdout?
You don't have to wait. Just send everything as you read it. That's what your code already does. Get rid of non-blocking mode; get rid of the while(wait(...)) condition; get rid of the final read; and just perform the first read loop until end of stream. Then call wait() to get the exit code.
If the process also produces on stderr you will need to read that in another thread, otherwise when the stderr buffer fills, it will block.
I am using the following code to redirect stdout to a pipe, then read all the data from the pipe to a buffer. I have 2 problems:
first problem: when i send a string (after redirection) bigger then the pipe's BUFF_SIZE, the program stops responding (deadlock or something).
second problem: when i try to read from a pipe before something was sent to stdout. I get the same response, the program stops responding - _read command stuck's ...
The issue is that i don't know the amount of data that will be sent to the pipe after the redirection.
The first problem, i don't know how to handle and i'll be glad for help. The second problem i solved by a simple workaround, right after the redirection i print space character to stdout. but i guess that this solution is not the correct one ...
#include <fcntl.h>
#include <io.h>
#include <iostream>
#define READ 0
#define WRITE 1
#define BUFF_SIZE 5
using namespace std;
int main()
{
int stdout_pipe[2];
int saved_stdout;
saved_stdout = _dup(_fileno(stdout)); // save stdout
if(_pipe(stdout_pipe,BUFF_SIZE, O_TEXT) != 0 ) // make a pipe
{
exit(1);
}
fflush( stdout );
if(_dup2(stdout_pipe[1], _fileno(stdout)) != 0 ) //redirect stdout to the pipe
{
exit(1);
}
ios::sync_with_stdio();
setvbuf( stdout, NULL, _IONBF, 0 );
//anything sent to stdout goes now to the pipe
//printf(" ");//workaround for the second problem
printf("123456");//first problem
char buffer[BUFF_SIZE] = {0};
int nOutRead = 0;
nOutRead = _read(stdout_pipe[READ], buffer, BUFF_SIZE); //second problem
buffer[nOutRead] = '\0';
// reconnect stdout
if (_dup2(saved_stdout, _fileno(stdout)) != 0 )
{
exit(1);
}
ios::sync_with_stdio();
printf("buffer: %s\n", buffer);
}
Your problem is that you are using blocking I/O calls, while both ends of the pipe are connected to the same process. If you don't know how much data there will be, this is just a deadlock situation waiting to happen.
printf is a blocking call, which means that it will not return until all data has been written to the output device (the pipe in this case), or until a write error is signalled (for example, the other end of the pipe is closed).
_read works similarly. It only returns when it has a full buffer worth of data or it knows that the end of the input has been reached (which can be signalled by closing the write-end of the pipe).
The only ways around this are
to use non-blocking I/O (which is not feasible if you don't have access to the code that calls printf), or
to ensure the reading and writing happens in different processes or threads, or
to use a temporary file for buffering, instead of the buffer of a pipe.
Pipes are unidirectional. Ie. you can either write to a pipe (x)or you can read from it.
To simulate a pipeline, try the following (the below is C, not C++):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc)
{
int pfds[2];
pipe(pfds);
if (!fork()) {
close(1); /* close stdout, check for errors */
dup(pfds[1]); /* make stdout same as pfds[1], dup reuses lowest fd */
close(pfds[0]); /* not needed */
execlp("ls", "ls", NULL); /* or write() in whatever way you want */
} else {
close(0); /* close stdin, check for errors please! */
dup(pfds[0]); /* make stdin same as pfds[0] */
close(pfds[1]); /* not needed on this end */
execlp("wc", "wc", "-l", NULL); /* or read() */
}
return 0;
}
[edit] By the way, your code does not overflow a buffer. Its only relation to buffer overflow is that you're reading into a statically allocated array...if you read() more than sizeof buffer elements, then you'll run into problems.
You must use non-blocking I/O if you don't want read or write to be blocked in this case.