Archive for June, 2010

Communicating from a C++ program to another process via a pipe

Suppose we have a C++ program that needs a large number of calculations in GNU bc done as quickly as possible. Using popen to start a new instance of bc for every calculation is unacceptable as it leads to an enormous overhead. We can start bc using execl and then use a fork+pipe construction to communicate with bc over a pipe.

An example program is given below:


#include <iostream>
#include <string>
#include <sstream>

#include <sys/wait.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

using namespace std;

int main(int argc, char *argv[])
{
int pread[2];
int pwrite[2];
pid_t cpid;
char buf;
if (pipe(pread) == -1) { perror("pipe"); exit(EXIT_FAILURE); }
if (pipe(pwrite) == -1) { perror("pipe"); exit(EXIT_FAILURE); }

cpid = fork();

if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); }
if (cpid == 0) {
close(pread[1]);
close(pwrite[0]);
dup2(pwrite[1],STDOUT_FILENO);   /* make 1 same as write-to end of pipe  */
dup2(pread[0],STDIN_FILENO);   /* make 0 same as read-from end of pipe */
execlp("bc", "bc", "-l", NULL);
exit(EXIT_FAILURE);
} else {            /* Parent writes argv[1] to pipe */
close(pread[0]);
close(pwrite[1]);
string s("2+2\n");
write(pread[1], s.c_str(), s.size());
char s2;
stringstream ss;
do
{
read(pwrite[0], &s2, 1);
ss << s2;
}
while (s2 != '\n');

int number;
ss >> number;
assert(number == 4);

s = "2+3\n";
write(pread[1], s.c_str(), s.size());
ss.str("");
do
{
read(pwrite[0], &s2, 1);
ss << s2;
}
while (s2 != '\n');
ss >> number;
assert(number == 5);

s = "quit\n";
write(pread[1], s.c_str(), s.size());

close(pread[1]);
close(pwrite[0]);

cout << "finished\n";

exit(EXIT_SUCCESS);
}
}

reference: http://www.cs.uleth.ca/~holzmann/C/system/pipeforkexec.html

Tuesday, June 8th, 2010 Uncategorized No Comments