When I'm trying to write to one of my pipes to communicate with a child process, it gets stuck. My first guess was that it was because its buffer was full, and something has to read from it, for it to continue, so I followed Increasing the maximum pipe size in linux instructions, and to my surprise, my maximum buffer size is 1048576. I'm trying to write 160000 bytes into my pipe. I don't understand why it's getting stuck.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <math.h>
#define SIZE 320000
#define FILENAME "Practical_Q_1numbers.txt"
extern long fun(long a, long b);
void write_numbers(int process_id,int* pipefds, long* numbers) {
long process_numbers[SIZE / 8];
memcpy(process_numbers, &numbers[SIZE / 8 * process_id], SIZE / 8 * sizeof(long));
printf("This gets printed\n");
// Pipe Limit
write(pipefds[1], process_numbers, SIZE / 8 * sizeof(long));
printf("This doesnt\n");
}
// Correct
long calculate(long* numbers, int left, int right) {
if(left == right){
return numbers[left];
}else if(left 1 == right) {
return fun(numbers[left], numbers[right]);
}
int middle = (right left) / 2;
long l_ans = calculate(numbers, left, middle);
long r_ans = calculate(numbers, middle 1, right);
return fun(l_ans, r_ans);
}
void calculateHelper(int id, int* pipefds) {
long* ptr = (long*)malloc(SIZE / 8 * sizeof(long));
read(pipefds[0], ptr, SIZE / 8 * sizeof(long));
long res = calculate(ptr, 0, SIZE / 8 - 1);
// write(pipefds[1], &res, sizeof(res));
return;
}
int main() {
// Read the file as parent.
FILE *myFile;
myFile = fopen(FILENAME, "r");
long* ptr = (long*)malloc(SIZE * sizeof(long));
// Reads correctly
for(int i = 0; i < SIZE; i ) {
fscanf(myFile, "%ld", &ptr[i]);
}
int pipefds[8][2];
for(int i = 0; i < 8; i ) {
pipe(pipefds[i]);
}
for(int i = 0; i < 1; i ) {
write_numbers(i,pipefds[i], ptr);
pid_t a = fork();
if(a == 0) {
// Child process
calculateHelper(i,pipefds[i]);
exit(0);
}
}
// Wait for your children to terminate
while(wait(NULL) > 0);
// long* finalContenders = (long*) malloc(8 * sizeof(long));
// for(int i = 0; i < 8; i ) {
// read(pipefds[i][0], &finalContenders[i], sizeof(long));
// }
// long ans = calculate(finalContenders, 0, 7);
// printf("%ld\n",ans);
}
Fun is a function responsible for calculating the GCD of 2 numbers.
CodePudding user response:
Your problem is here:
for(int i = 0; i < 1; i ) {
write_numbers(i,pipefds[i], ptr);
pid_t a = fork();
if(a == 0) {
// Child process
calculateHelper(i,pipefds[i]);
exit(0);
}
You write the data to the pipe before there's a process to read from it. That's deadlock-prone no matter how large the maximum pipe buffer size might be.
This would be better:
for(int i = 0; i < 1; i ) {
pid_t a = fork();
if(a == -1) {
// handle error
}
else if(a == 0) {
// Child process
calculateHelper(i,pipefds[i]);
exit(0);
}
else {
write_numbers(i,pipefds[i], ptr);
}
You'd also be better off writing smaller chunks to the pipe no matter what. Right now, you don't handle partial write()
results at all (bolding mine):
The
write()
function shall attempt to writenbyte
bytes from the buffer pointed to bybuf
to the file associated with the open file descriptor,fildes
.
There's no portable guarantee on any call to write()
that the entirety of your requested buffer will be written.
The easiest way to do that is to create a writeAllBytes()
wrapper around write, such as:
#define CHUNK_SIZE ( 4 * 1024 )
ssize_t writeAllBytes( int fd, void *data, size_t bytes )
{
// need to do pointer arithmetic on the value so
// it can't be a void *
char *buf = data;
ssize_t totalWritten = -1;
while ( bytes > 0 )
{
size_t bytesToWrite = bytes;
if ( bytesToWrite > CHUNK_SIZE )
{
bytesToWrite = CHUNK_SIZE;
}
ssize_t bytesWritten = write( fd, buf, bytesToWrite );
if ( bytesWritten <= 0 )
{
break;
}
buf = bytesWritten;
totalWritten = bytesWritten;
bytes -= bytesWritten;
}
return( totalWritten );
}
Similarly, a corresponding readAllBytes()
would also be appropriate.