Chatting with a Thread

A launched thread can be passed an argument, similar to any function. And the thread can return a value, just like any function. But while the thread runs, options for communications are rather limited.

One way to chat with a running thread is to create a pipe, as covered in last week’s Lesson. The pipe is created before the thread is launched, setting input and output file descriptors. The output file descriptor is passed to the thread as an argument, allowing the main program to send data to the thread through the pipe.

The following code demonstrates this process. A thread is created, then it waits for input from the pipe and outputs the result.

2022_07_02-Lesson.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>

void *patiently(void *p)
{
    int fd;
    char buffer[BUFSIZ];

    fd = *(int *)p;

    while( read(fd,buffer,BUFSIZ) == 0 )
        sleep(1);
    printf("The thread has received: %s",buffer);

    return(NULL);
}

int main()
{
    char buffer[BUFSIZ];
    int fp[2];
    pthread_t thd;
    int r;

    /* open the pipe */
    r = pipe(fp);
    if( r==-1 )
    {
        perror("Pipe");
        exit(1);
    }

    /* spawn the thread, passing it the read
       end of the pipe */
    r = pthread_create( &thd, NULL, patiently, (void *)&fp[0] );
    if( r!=0 )
    {
        perror("Thread");
        exit(1);
    }

    /* interact with the thread */
    printf("Send some text to the thread: ");
    fgets(buffer,BUFSIZ,stdin);
    write(fp[1],buffer,strlen(buffer));

    puts("Press Enter:");
    getchar();

    return(0);
}

The patiently() function is launched as a thread from the main() function. Its argument is a void pointer, standard for all threads. Internally, this pointer’s value is saved in int variable fd. The ugly conversion takes place at Line 11:

fd = *(int *)p;

The void pointer p must be cast to an int pointer (int *), then the * operator fetches value at that address, which is stored in variable fd. I set this weird-ass construction as its own statement to keep the read() function at Line 13 from looking overly complex. Variable fd acts as the output file descriptor for the pipe created in the main() function. (The output is generated by the main() function.)

As the patiently() thread is unsynchronized with the main() thread (more on this topic at the end of the post), a while loop at Line 13 polls the read() function. This function returns zero when nothing has been read, so the loop sleeps one second and repeats. A more sophisticated approach would be to use the select() or poll() functions here, but I didn’t want this example to go too far into the weeds.

Once data is read, the printf() statement at Line 15 outputs the results, then the thread terminates.

In the main() program, a pipe is created at Line 28 using int array fp[]. The patiently() function is launched as a thread at Line 37 with the pipe’s input end file descriptor as its argument. Here’s the ugly format:

(void *)&fp[0]

The address-of operator & is required as fp[0] is an integer value, not the entire array. This address must be typecast void to be swallowed properly as a pipe() function argument.

Line 45 prompts the user for input, gathered at Line 46. Line 47 uses the write() function to send the input string through the created pipe to the spawned thread, where it’s processed.

Here is a sample run:

Send some text to the thread: Hello, Mr. Thread!
Press Enter:
The thread has received: Hello, Mr. Thread!

The Press Enter prompt the main() function outputs appears before the thread’s output (at least on my system). This behavior illustrates how the two threads are unsynchronized, which is an issue when communicating with any thread.

It’s possible to synchronize activity in a thread, as well as provide interprocess communications, by using semaphores and mutexes. I may cover these topics in the future, but be aware that successful communications with a thread should involve some level of synchronization, which is why these extra techniques are available.

Leave a Reply