I'm experimenting on how to communicate between a thread and the main function in C There is a behavior that I don't understand in the following code :
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
void* output(void* pipe1);
int main(int argc, const char *argv[])
{
pthread_t tid0;
int pipe1[2];
char buffer[200];
// Creating the pipe
pipe(pipe1);
// Creating the thread and passing the pipe as argument
pthread_create(&tid0, NULL, output, &pipe1);
// Input from user
scanf("%s", buffer);
// Writing to the pipe
write(pipe1[1], buffer, strlen(buffer));
return 0;
}
void* output(void* pipe1) {
char buffer[200];
// Reading the pipe and print the buffer
read(((int*)pipe1)[0], buffer, strlen(buffer));
printf("thread say: %s\n", buffer);
pthread_exit(NULL);
}
Why the read function doesn't block on the pipe's file descriptor ?
Maybe I should close the end of the pipe but since they share the same memory space, the error "bad file descriptor" is returned when I will call read or write.
Maybe you can guide me to other methods if pipe is really a bad solution (with an example it will be amazing ! :) )
Many thanks !
EDIT: SOLUTION
Many thank for your answer here is the code that have the expected behavior
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void* output(void* pipe1);
int main(int argc, const char *argv[])
{
pthread_t tid0;
int pipe1[2];
char buffer[200];
// Creating the pipe
pipe(pipe1);
// Creating the thread and passing the pipe as argument
pthread_create(&tid0, NULL, output, &pipe1);
// Input from user
scanf("%s", buffer);
// Writing to the pipe
if (write(pipe1[1], buffer, strlen(buffer)) < 0) {
perror("write");
exit(1);
}
// join so the main "wait" for the thread
pthread_join(tid0, NULL);
return 0;
}
void* output(void* pipe1) {
char buffer[200];
int nread;
// Reading the pipe and print the buffer
nread = read(((int*)pipe1)[0], buffer, sizeof buffer - 1);
if (nread < 0) {
fprintf(stderr, "ERROR\n");
perror("read");
exit(1);
}
buffer[nread] = '\0';
fprintf(stderr, "thread say: %s\n", buffer);
pthread_exit(NULL);
}
char buffer[200];
read(((int*)pipe1)[0], buffer, strlen(buffer));
You are calling strlen
on an uninitialized buffer. This is allowed to crash your program. Instead, you got lucky, and all it did was tell read
to read zero bytes, so read
returned without doing anything.
What you actually want is
ssize_t nread = read(((int *)pipe1)[0], buffer, sizeof buffer - 1);
if (nread < 0) {
perror("read");
return 0;
}
buffer[nread] = '\0';
What read
wants to be told is how much space you are giving it to read into, not the length of any string that may or may not already be in that space. That's sizeof buffer
, minus one so we always have space to add a string terminator.
It's correct to use strlen
when writing, because you only want to write the actual string, not any junk that might be beyond the end of the string; but then write
doesn't write the string terminator to the pipe, so read
doesn't read one, so you have to add it by hand. And, of course, always check for errors.
Also, keep in mind that the threads run simultaneously. Even after fixing this bug, the write
may already have happened by the time the reader-thread calls read
, and if it hasn't, it probably will happen very soon. If you want to observe the reader-thread actually blocking in read
you need to delay before calling write
.