简体   繁体   中英

Multithreaded Chat Program in C using Pipes

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM