I don't think there is any good way for a process to write text to its own stdin
; stdin
is meant to be a way for the parent process (or the user, if the parent process is a Terminal window) to send data to your process, not for your process to send data to itself.
However, you could achieve a similar result by having your child thread use select() or similar to read input from both stdin
and from the output end of a pipe; then your parent process can send data to the child process by writing to the input end of that same pipe.
Below is a modified version of your program demonstrating the technique. Note that the child thread will print out any text that you type into stdin
; and also the main thread will send a line of text to the child thread once every 5 seconds, and the child thread will also print out that text. After the main thread has sent 5 messages to the child thread, the main thread will close its end of the pipe, causing the child thread to exit and then the process can exit cleanly as well.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/select.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
static int pipeReadFD = -1;
static int ReadTextFrom(const char * descriptionOfSender, int fd)
{
char buf[256];
const int numBytesRead = read(fd, buf, sizeof(buf)-1); // -1 so we always have room to place NUL terminator byte
if (numBytesRead > 0)
{
buf[numBytesRead] = '\0'; // make sure the string is NUL-terminated
printf("ReadTextFrom(): Read %i bytes from [%s]: [%s]\n", numBytesRead, descriptionOfSender, buf);
}
return numBytesRead;
}
void* init_on_sys_ready(void* terminalflag)
{
int num=0;
printf("Child thread: trying to read text from stdin\n");
while(1)
{
const int stdinFD = fileno(stdin);
const int maxFD = (pipeReadFD > stdinFD) ? pipeReadFD : stdinFD;
fd_set readFDSet;
FD_ZERO(&readFDSet);
FD_SET(stdinFD, &readFDSet);
FD_SET(pipeReadFD, &readFDSet);
const int selRet = select(maxFD+1, &readFDSet, NULL, NULL, NULL);
if (selRet >= 0)
{
if ((FD_ISSET(stdinFD, &readFDSet))&&(ReadTextFrom("stdin", stdinFD) <= 0)) break;
if ((FD_ISSET(pipeReadFD, &readFDSet))&&(ReadTextFrom("pipe", pipeReadFD) <= 0)) break;
}
else
{
perror("select");
break;
}
}
printf("Child thread exiting!\n");
return NULL;
}
int main(int argc, char ** argv)
{
int pipeFDs[2];
if (pipe(pipeFDs) < 0)
{
perror("pipe");
return -1;
}
pipeReadFD = pipeFDs[0];
int pipeWriteFD = pipeFDs[1];
pthread_t tid;
if (pthread_create(&tid, NULL, &init_on_sys_ready, NULL) != 0) {
printf("Failed to initialize CLI\n");
exit(1);
}
int count = 0;
for (int count=0; count < 5; count++)
{
char buf[512];
snprintf(buf, sizeof(buf), "Hello #%i from main thread", ++count);
const size_t slen = strlen(buf);
if (write(pipeWriteFD, buf, slen) == slen)
{
printf("main() sent [%s] to the child thread via the pipe.\n", buf);
}
else
{
perror("write");
break;
}
sleep(5);
}
close(pipeWriteFD); // this will cause the child thread to exit ASAP
pthread_join(tid, NULL);
return 0;
}