Multithreaded Chat Program in C using Pipes - c

For a class assignment I am required to develop a single program, that -when opened in two separate windows - allows the user to type on one window and have the entered text appear on the other, while the other window can also type and have their text appear on the first window.
This was first implemented using two separate programs, one which read the input from stdin, wrote it to a pipe, called fflush on the pipe, then got data from the pipe and put it into stdout before calling fflush on stdout, and the other which did basically the exact opposite.
I'm here because I'm struggling to make the single program version work and I'm not sure if I understand threading correctly.
Here's my main function:
int main()
{
pthread_t threadID[2];
pthread_mutex_init(&globalLock, NULL);
pthread_create(&threadID[0], NULL, InputToPipe, NULL);
pthread_create(&threadID[1], NULL, PipeToOutput, NULL);
pthread_join(threadID[0], NULL);
pthread_join(threadID[1], NULL);
pthread_mutex_destroy(&globalLock);
return 0;
}
As I understand it, this will initialize a global lock (which I'm not sure if I need or not) and then create two threads. The first thread will call InputToPipe and the second will call PipeToOutput. Both should enter their respective functions nearly simultaneously. Once in InputToPipe (which looks like this)
void *InputToPipe()
{
pthread_mutex_lock(&globalLock);
char buffer[100];
FILE *output = fopen("my.pipe2", "w");
if (output == NULL)
{
printf("Error opening pipe\n");
return NULL;
}
while (fgets(buffer, sizeof(buffer), stdin))
{
fputs(buffer, output);
fflush(output);
}
pthread_mutex_unlock(&globalLock);
return NULL;
}
A lock is set, which was intended to keep the second instance of the program from accessing the first function. I thought that this would cause the second instance of the program to only run the PipeToOutput function (shown below),
void *PipeToOutput()
{
char buffer[100];
FILE *input = fopen("my.pipe", "r");
if (input == NULL)
{
printf("Error opening pipe\n");
return NULL;
}
while (fgets(buffer, sizeof(buffer), input))
{
fputs(buffer, stdout);
fflush(stdout);
}
return NULL;
}
but instead I think it would block the second program from doing anything as the first pipe is joined first, and that cannot be done until it is unlocked by the first program, which will not happen before the program is terminated. Needless to say, I am confused and pretty sure that most of my logic is off, but I was unable to find examples or explanations about using two threads to run two different functions in two different console windows (unless I completely misunderstood the assignment somehow and it's just one function running twice, but I don't think that's the case). I would appreciate either some help fixing this program so I can use it as an example to understand what the threads are doing, or just an explanation on how I would implement the threads and why. I know it's probably stupidly simple but I am having trouble with the concept. Thanks in advance.

If the idea is that my.pipe is used to transfer messages from the first program to the second, and my.pipe2 is used to transfer messages in the opposite direction, then it appears that both programs should be identical except swapping my.pipe and my.pipe2.
It sounds like they want each program to have two threads, one of which is responsible for reading from the first pipe and writing to stdout, and the other responsible for reading from stdin and writing to the second pipe.
That being the case, your existing functions look correct with the exception that you don't need the lock at all - all it's doing is stopping both threads from running at once, and your threads aren't sharing any state at all. Your second copy of the program would be the same except swapping my.pipe and my.pipe2 around.
Note that your InputToPipe and PipeToOutput functions contain an identical loop that differs only in the FILE * variables used, so you could separate that out into its own function:
void FileToFile(FILE *output, FILE *input)
{
char buffer[100];
while (fgets(buffer, sizeof(buffer), input))
{
fputs(buffer, output);
fflush(output);
}
}
void *InputToPipe()
{
FILE *output = fopen("my.pipe2", "w");
if (output == NULL)
{
printf("Error opening pipe\n");
return NULL;
}
FileToFile(output, stdin);
fclose(output);
return NULL;
}
void *PipeToOutput()
{
FILE *input = fopen("my.pipe", "r");
if (input == NULL)
{
printf("Error opening pipe\n");
return NULL;
}
FileToFile(stdout, input);
fclose(input);
return NULL;
}
In fact you could go further than this: if you opened the pipes in the main() process before starting the threads, you could just pass the pair of FILE *input and FILE *output variables to the thread functions, which would let you use the same thread function (with different parameters) for each thread.

Related

Call a C Program within Another and Get the Child's Output in macOS

I have two C programs and am trying to call some child program "child.c" inside of some parent program "parent.c", and capturing the output to stdout from child.c. How would I go about doing this?
I am using macOS.
Here's an example of what parent.c and child.c might look like
parent.c
while (1)
{
// call the child program
// capture the output from the child
if (child_output == some_condition)
{
break;
}
}
child.c
printf("Hello world!")
Thanks for the help.
Simply use popen() and create a stream object of type FILE * which you can use with fread()/fgets() to get the output from the child program. Reading the manual page should be enough to get you started.
But here is an example
#include <stdio.h>
int
main(void)
{
FILE *pipe;
char line[256];
pipe = popen("ls", "r");
if (pipe != NULL) {
while (fgets(line, sizeof line, pipe) != NULL) {
fprintf(stdout, "%s", line);
}
pclose(pipe);
}
return 0;
}
Also, read the manual to get an idea of how this actually works.

Look for popen output changes

I need to create a program that does this:
execute a command with popen
do things with the output of popen(use the FILE in a lot of things)
stay checking for popen output changes, if have one, re execute everything.
The source code is here: https://gitorious.org/clyv/clyv
So I only want to execute all the rest of the program AGAIN if there is a change in the output of popen (must be compared with the first output)
The program should do everything first time, and after, only do everything and print again if there is a change on popen output. The popen should verified once a second.
Update
I didn't get any answer that solve my problem here, but reading a C tutorial i saw something about threads, and it sounds like the solution to me, i will see what i can do.
You are free to call popen() as many times as needed. But, to properly release resources used by a call to popen(), you need to call pclose().
In your case, you probably want to just poll the output occasionally, and emit something whenever it is necessary to do so.
first_time = 1;
need_to_print = 1;
for (;;) {
FILE *fp = popen(...);
/* read input ... */
pclose(fp);
/* parse input ... */
if (first_time) {
/* save contents for future comparison... */
first_time = 0;
} else {
need_to_print = /* result of comparing saved contents with new contents */;
}
if (need_to_print) {
/* print something ... */
}
sleep(INTERVAL);
}
You can use
//an array of 2 string buffers
char output[2][1024];
//the string buffer index in use
int flip = 0;
FILE *fp;
void executeTestCommand() {
int resultSize;
fp = popen("free -m | awk 'NR==3 {print $3}'" "r");
if (fp == NULL) {
perror("Failed to run command");
}
else {
result_size = fread(output, 1, 1024 - 1, fp);
//place string terminator
output[flip][result_size] = '\0';
}
//flip the buffers
flip = flip ^ 1;
pclose(fp);
}
int main() {
//init with empty string
output[0][0] = '\0';
output[1][0] = '\0';
//for ever
for(;;) {
executeTestCommand();
//if the last command output differs from the current
//command output
if (strcmp(output[0], output[1])) {
//execute the rest of the command here
}
}
return 0;
}
Cheers!
You want to close the file pointer (you don't want any memory leaks) since you are going to use the same FILE * fp variable again with popen.
Later edit: hope it helps:). You might want to insert a sleep statement inside the for ever block because this will be cpu intensive.
#AlinUngureanu #JonathanLeffler #jxh
I published the source on git! Now you can see what i want
https://gitorious.org/clyv/clyv

Writing to global file with threads in C

I'm having an issue with being able to write to a file I've created globally, initialized in main (successfully), and writing to in a function used by multiple threads (on Linux).
#includes
FILE *f;
main(){
// Create threads successfully
f = fopen("fileName.txt", "w");
// Make sure the file was able to be created
if(f = NULL){
printf("Unable to create file");
exit(1);
}
// This much works, the check indicates the file was created
// successfully when I run it
while(1){
// loops for a while, getting input from user to direct threads
// When end is determined, waits for all the threads to finish,
// clears allocated memory, and closes file then returns
fclose(f);
return;
}
}
void *threadProcess(){
// Do stuff
// This printf works fine using the values i give the function, as is here
// The values are determined in 'Do stuff'
printf("%d trying to write \"%d BAL %d TIME %d.%06d %d.%06d\" to the file\n", cid, tmp->reqNum, balance, tmp->seconds, tmp->useconds, endTime.tv_sec, endTime.tv_usec);
fflush(stdout);
// There appears to be a Segmentation fault here
fprintf(f, "%d BAL %d TIME %d.%06d %d.%06d\n", tmp->reqNum, balance, tmp->seconds, tmp->useconds, endTime.tv_sec, endTime.tv_usec);
// Never gets here
}
What am I doing wrong here? As I said, the printf statement right before the fprintf statement works and outputs the correct stuff.
Am I wrong to assume that would ensure I don't have an pointer issues for fprintf?
Thanks
it was in my if(reqLog = NULL) check.... I was assigning not comparing. Sorry to have wasted your time haha. – tompon

popen vs system function in C

Is The benefit of using popen is only to read the ouput produced by a command or there are some more benefits or advantages of popen over system.
Consider two programs below:
Program 1:
#include <stdio.h>
int main()
{
FILE *more,*who;
if (!(more = popen("more", "w")))
{
printf("Command `more` not found!");
return -1;
}
if (!(who = popen("who", "r")))
{
printf("Command `who` not found!");
return -1;
}
while (!feof(who))
{
char buffer[100];
if (fgets(buffer, 100, who) != NULL)
{
fputs(buffer, more);
}
}
fclose(more);
fclose(who);
return 0;
}
Program 2:
#include <unistd.h>
int main()
{
system("who|more");
return 0;
}
Why should i use Program1 if i can do the same thing in one line as done in Program2.
The two programs you have provided as examples are not equivalent. popen gives you a pair of file handles you can use to read and write input and output to and from stdin/stdout of the running process in an interactive manner. The system call is merely executing that and redirecting stdin of the current process to that of the invoked child process, and stdout of that process to stdout of the current (host) process.
It depends what you are trying to achieve, in general. If your goal is simply to run a command, system works fine. If you're interested in reading its output in a programmatic manner and processing it (and possibly generating more input), then popen is going to work better.

C: writing the following code into functions

Dear respected programmers. Please could you help me (again) on how to put the following code into functions for my program.
I have read on-line and understand how functions work but when I do it myself it all goes pear shaped/wrong(I am such a noob).
Please could you help with how to for example to write the code below into functions.(like opening the input file).
My initial code looks like:
main (int argc, char **argv)
{
int bytes_read, bytes_written;
struct stat inode;
int input_fd, output_fd;
char buffer[64];
int eof = 0;
int i;
/* Check the command line arguments */
if (argc != 3)
{
printf("syntax is: %s \n", <fromfile> <tofile>\n", argv[0]);
exit (1);
}
/* Check the input file exists and is a file */
if ((stat(argv[1], &inode) == -1) || (!S_ISREG(inode.st_mode)))
{
printf("%s is not a file\n", argv[1]);
exit(2);
}
/* Check that the output file doesnt exist */
if (stat(argv[2], &inode) != -1)
{
printf("Warning: The file %s already exists. Not going to overwrite\n", argv[2]);
exit(2);
}
/* Open the input file for reading */
input_fd = open(argv[1], O_RDONLY, 0);
if (input_fd == -1)
{
printf("%s cannot be opened\n", argv[1]);
exit(3);
}
output_fd = open(argv[2], O_CREAT | O_WRONLY | O_EXCL , S_IRUSR|S_IWUSR);
if (output_fd == -1)
{
printf("%s cannot be opened\n", argv[2]);
exit(3);
}
/* Begin processing the input file here */
while (!eof)
{
bytes_read = read(input_fd, buffer, sizeof(buffer));
if (bytes_read == -1)
{
printf("%s cannot be read\n", argv[1]);
exit(4);
}
if (bytes_read > > 0)
{
bytes_written = write(output_fd, buffer, bytes_read);
if (bytes_written == -1)
{
printf("There was an error writing to the file %s\n",argv[2]);
exit(4);
}
if (bytes_written != bytes_read)
{
printf("Devistating failure! Bytes have either magically appeared and been written or dissapeard and been skipped. Data is inconsistant!\n");
exit(101);
}
}
else
{
eof = 1;
}
}
close(input_fd);
close(output_fd);
}
My attempt at opening an output file:
void outputFile(int argc, char **argv)
{
/* Check that the output file doesnt exist */
if (stat(argv[argc-1], &inode) != -1)
{
printf("Warning: The file %s already exists. Not going to overwrite\n", argv[argc-1]);
return -1;
}
/*Opening ouput files*/
file_desc_out = open(argv[i],O_CREAT | O_WRONLY | O_EXCL , S_IRUSR|S_IWUSR);
if(file_desc_out == -1)
{
printf("Error: %s cannot be opened. \n",argv[i]); //insted of argv[2] have pointer i.
return -1;
}
}
Any help on how I would now reference to this in my program is appreciated thank you.
I tried:
ouputfile (but I cant figure out what goes here and why either).
Maybe the most useful function for you is:
#include <stdio.h>
#include <stdarg.h>
extern void error_exit(int rc, const char *format, ...); /* In a header */
void error_exit(int rc, const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(rc);
}
You can then write:
if (stat(argv[2], &inode) != -1)
error_exit(2, "Warning: The file %s exists. Not going to overwrite\n",
argv[2]);
Which has the merit of brevity.
You write functions to do sub-tasks. Deciding where to break up your code into functions is tricky - as much art as science. Your code is not so big that it is completely awful to leave it as it is - one function (though the error handling can be simplified as above).
If you want to practice writing functions, consider splitting it up:
open_input_file()
open_output_file()
checked_read()
checked_write()
checked_close()
These functions would allow your main code to be written as:
int main(int argc, char **argv)
{
int bytes_read;
int input_fd, output_fd;
char buffer[64];
if (argc != 3)
error_exit(1, "Usage: %s <fromfile> <tofile>\n", argv[0]);
input_fd = open_input_file(argv[1]);
output_fd = open_output_file(argv[2]);
while ((bytes_read = checked_read(input_fd, buffer, sizeof(buffer)) > 0)
check_write(output_fd, buffer, bytes_read);
checked_close(input_fd);
checked_close(output_fd);
return 0;
}
Because you've tucked the error handling out of sight, it is now much easier to see the structure of the program. If you don't have enough functions yet, you can bury the loop into a function void file_copy(int fd_in, int fd_out). That removes more clutter from main() and leaves you with very simple code.
Given an initial attempt at a function to open the output file:
void outputFile(int argc, char **argv)
{
/* Check that the output file doesnt exist */
if (stat(argv[argc-1], &inode) != -1)
{
printf("Warning: The file %s already exists. Not going to overwrite\n", argv[argc-1]);
return -1;
}
/*Opening ouput files*/
file_desc_out = open(argv[i],O_CREAT | O_WRONLY | O_EXCL , S_IRUSR|S_IWUSR);
if(file_desc_out == -1)
{
printf("Error: %s cannot be opened. \n",argv[i]); //insted of argv[2] have pointer i.
return -1;
}
}
Critique:
You have to define the variables used by the function in the function (you will want to avoid global variables as much as possible, and there is no call for any global variable in this code).
You have to define the return type. You are opening a file - how is the file descriptor going to be returned to the calling code? So, the return type should be int.
You pass only the information needed to the function - a simple form of 'information hiding'. In this case, you only need to pass the name of the file; the information about file modes and the like is implicit in the name of the function.
In general, you have to decide how to handle errors. Unless you have directives otherwise from your homework setter, it is reasonable to exit on error with an appropriate message. If you return an error indicator, then the calling code has to test for it, and decide what to do about the error.
Errors and warnings should be written to stderr, not to stdout. The main program output (if any) goes to stdout.
Your code is confused about whether argv[i] or argv[argc-1] is the name of the output file. In a sense, this criticism is irrelevant once you pass just the filename to the function. However, consistency is a major virtue in programming, and using the same expression to identify the same thing is usually a good idea.
Consistency of layout is also important. Don't use both if( and if ( in your programs; use the canonical if ( notation as used by the language's founding fathers, K&R.
Similarly, be consistent with no spaces before commas, a space after a comma, and be consistent with spaces around operators such as '|'. Consistency makes your code easier to read, and you'll be reading your code a lot more often than you write it (at least, once you've finished your course, you will do more reading than writing).
You cannot have return -1; inside a function that returns no value.
When you a splitting up code into functions, you need to copy/move the paragraphs of code that you are extracting, leaving behind a call to the new function. You also need to copy the relevant local variables from the calling function into the new function - possibly eliminating the variables in the calling function if they are no longer used there. You do compile with most warnings enabled, don't you? You want to know about unused variables etc.
When you create the new function, one of the most important parts is working out what the correct signature of the function is. Does it return a value? If so, which value, and what is its type? If not, how does it handle errors? In this case, you probably want the function to bail out (terminate the program) if it runs into an error. In bigger systems, you might need to consistently return an error indicator (0 implies success, negative implies failure, different negatives indicating different errors). When you work with function that return an error indicator, it is almost always crucial that you check the error indicators in the calling code. For big programs, big swathes of the code can be all about error handling. Similarly, you need to work out which values are passed into the function.
I'm omitting advice about things such as 'be const correct' as overkill for your stage in learning to program in C.
you seem to actually understand how to make a function. making a function really isnt that hard. first, you need to kind of understand that a function has a type. in otherwords, argc has type int and argv has type char *, your function (currently) has type void. void means it has no value, which means when you return, you return nothing.
however, if you look at your code, you do return -1. it looks like you want to return an interger. so you should change the top from void outputfile(...) to int outputfile(...).
next, your function must return. it wont compile if there is a circumstance where it won't return (besides infinite loops). so at the very bottom, if no errors happen, it will reach the end. since you're no longer using "void" as the return type, you must return something before the end of the function. so i suggest putting a return 1; to show that everything went great
There's several things.
The function return type isn't what you want. You either want to return a file descriptor or an error code. IIRC, the file descriptor is a nonnegative int, so you can use a return type of int rather than void. You also need to return something on either path, either -1 or file_desc_out.
You probably don't want to pass in the command-line arguments as a whole, but rather something like argv[argc - 1]. In that case, the argument should be something like char * filename rather than the argc/argv it has now. (Note that the argv[i] you've got in the last printf is almost certainly wrong.)
This means it would be called something like
int file_desc_out = outputFile(argv[argc - 1]);
You need to have all variables declared in the function, specifically inode and file_desc_out.
Finally, put an extra level of indentation on the code inside the { and } of the function itself.

Resources