I have 3 threads - I have to read something in the first one, count characters in the second, and make an output in the third. So I'm using two pipes here; for the 1st - 2nd threads, and 2nd - 3rd.
However, it doesn't work at all. I mean, I can type the string in the console, but then nothing happenes, there's no output.
What's wrong here?
Also, is this possible to add something like "Type string here: " in the first thread somewhere? Adding it in the while loop seems to produce strange results - it displays randomly after running the program :P
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/stat.h>
#include <pthread.h>
#include <string.h>
int first[2];
int second[2];
void *input(void *ptr)
{
while(1)
{
char str[100];
int result;
result = read(STDIN_FILENO, str, sizeof(str));
if(result <= 0)
{
if(result == -1)
perror("read");
close(first[1]);
exit(2);
}
if(write(first[1], str, result) != result)
{
perror("write");
exit(2);
}
}
}
void *countChars(void *ptr)
{
int result, result2, count = 0;
char str[100];
while(1)
{
result = read(first[0], str, sizeof(str));
if(result <= 0)
{
if(result == -1)
perror("read");
close(first[0]);
close(second[1]);
exit(2);
}
if(write(STDOUT_FILENO, str, result) != result)
{
perror("write");
exit(2);
}
while(str[count] != '\0') count++;
write(second[1], &count, sizeof(count));
}
}
void *output(void *ptr)
{
int result2, count = 0;
char str[100];
while(1)
{
result2 = read(second[0], str, sizeof(str));
if(result2 <= 0)
{
if(result2 == -1)
perror("read");
close(second[0]);
exit(2);
}
if(write(STDOUT_FILENO, str, result2) != result2)
{
perror("write");
exit(2);
}
while(str[count] != '\0') count++;
printf("Writer: %d\n", count - 1);
}
}
int main()
{
pthread_t t1, t2, t3;
if(pipe(first) == -1)
{
printf("First pipe error");
exit(1);
}
if(pipe(second) == -1)
{
printf("Second pipe error");
exit(1);
}
pthread_create(&t1, NULL, input, NULL);
pthread_create(&t2, NULL, countChars, NULL);
pthread_create(&t3, NULL, output, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
return 0;
}
You want the countChars function to count until a newline and write the int "count"
void *countChars(void *ptr)
{
int result, result2, count = 0;
char str[100];
while(1)
{
result = read(first[0], str, sizeof(str));
if(result <= 0)
{
if(result == -1)
perror("read");
close(first[0]);
close(second[1]);
exit(2);
}
if(write(STDOUT_FILENO, str, result) != result)
{
perror("write");
exit(2);
}
//while(str[count] != '\0') count++;
while(str[count] != '\n') count++;
write(second[1], &count, sizeof(count));
count = 0;
}
}
And the output function to read the sizeof an int into an int variable.
void *output(void *ptr)
{
int result2, count = 0;
//char str[100];
while(1)
{
//result2 = read(second[0], str, sizeof(str));
result2 = read(second[0], &count, sizeof(count));
if(result2 < sizeof(count))
{
close(second[0]);
exit(2);
}
printf("Writer: %d\n", count);
}
}
This works ok because only countChars is writing to the 2nd pipe. A pipe write/read is atomic up to PIPE_BUF chars and an int is way less than that so the reads are predictable.
Related
I'm writing a project where you start the server in one terminal, and in other terminals that are clients you can send messages from one user to another using FIFO pipes. Server creates FIFO pipe that reads messages from clients. Client creates FIFO pipe to read messages from server.
In one terminal to start the server I type ./projectname --start and in client i type ./projectname --login nickname. When I close the client terminal my server receives segmentation fault(core dumped) error message. I tried to get rid of this in every possible way I know for x hours. How can it be fixed?
I have also tried to register users using the void verifyloginclient(char *login) function but parent proccess is unable to receive information from child and is stuck in infinite while(1) sending some message to server that also crashes server with segmentation fault so it's commented for now.
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
char userlist[10][30];
int succesfulllogin = 1;
void handler(int signum){
pid_t pid;
pid = wait(NULL);
succesfulllogin = 0;
printf("Parent knows child %d finished\n", (int)pid);
printf("Parent ending...\n");
}
void sig_handler_parent(int signum){
printf("signal response from child!\n");
succesfulllogin = 0;
exit(0);
}
void sig_handler_child(int signum){
printf("signal from parent\n");
succesfulllogin = 0;
exit(0);
}
void verifyloginclient(char *login)
{
int fd;
char buf[256];
char buf2[256];
snprintf(buf, sizeof buf, "%s%s", "fifopipes/","serwer.fifo");
if((fd = open(buf, O_WRONLY)) == -1){
perror("openFdloginclient");
exit(EXIT_FAILURE);
}
snprintf(buf2, sizeof buf2, "%s%s%s", login, " /login ",login);
if((write(fd, buf2, strlen(buf2))) == -1){
perror("writeloginclient");
}
close(fd);
}
int verifyloginserwer(char *login)
{
// check if login is on the userlist
int flagcmp = -1;
int x;
int indeks=0;
for(int i=0;i<10;i++){
x = strcmp(&userlist[i][0],login);
if(x==0){
flagcmp = i;
}
}
if(flagcmp == -1){ //if it doesnt exist we add him to first free slot
for(int i=0;i<10;i++){
if(userlist[i][0]=='\0'){
strcpy(userlist[i],login);
printf("userlist: %s\n", userlist[i]);
succesfulllogin = 1;
break;
}
else{
indeks++;
}
}
}
else if(flagcmp != -1 || indeks==10){
fprintf(stderr, "loggin error!\n");
succesfulllogin = 0;
return 2;
}
return 0;
}
int splitstring(char *source, int desiredlength, char **s1,char **s2)
{
int len;
len = strlen(source);
if (desiredlength > len)
return(0);
*s1 = (char *) malloc(sizeof(char) * desiredlength);
*s2 = (char *) malloc(sizeof(char) * len-desiredlength+1);
if(s1 ==NULL || s2 == NULL)
return 0;
strncpy(*s1,source,desiredlength);
strncpy(*s2,source+desiredlength, len-desiredlength);
return(1);
}
void startserwer()
{
int fdserwer;
int fdanuluj;
int fd;
char readbuf[80];
int read_bytes;
char buf[256]; //pipe server
char buf2[256]; //pipe client
char buf3[256]; // message to client
for(int i=0;i<10;i++){ // declare userlist
userlist[i][0] = '\0';
}
snprintf(buf, sizeof buf, "%s%s", "fifopipes/","serwer.fifo");
umask(0);
if(mkfifo(buf, 0777) == -1){
perror("mkfifoserwer");
exit(EXIT_FAILURE);
}
while(1){
if((fdserwer = open(buf, O_CREAT | O_RDONLY))== -1){
perror("openFdserwer");
exit(EXIT_FAILURE);
}
if((read_bytes = read(fdserwer, &readbuf, sizeof(readbuf)))== -1){
perror("readbytes");
}
else{
readbuf[read_bytes] = '\0';
//SENDER LOGIN
char senderlogin[80];
strcpy(senderlogin, readbuf);
char *token = strtok(senderlogin, " ");
printf("%s\n", token);
strcpy(senderlogin, token);
int b;
char *loginnadawcy;
char *resztakomendy;
b = splitstring(readbuf, (int) strlen(token)+1,&loginnadawcy,&resztakomendy);
if(b!=1){
printf("error in command\n");
}
else{
loginnadawcy[strlen(token)]='\0';
//COMMAND NAME AFTER SLASH /
char command[80];
strcpy(command, readbuf);
token = strtok(NULL, " ");
printf("%s\n",token);
strcpy(command, token);
int a;
char *komenda;
char *reszta;
a = splitstring(resztakomendy, (int)strlen(token)+1,&komenda,&reszta);
if(a!=1){
printf("error\n");
}
else{
komenda[strlen(token)]='\0';
if(strcmp(komenda,"/login")==0){
if(verifyloginserwer(senderlogin)==2){
//open client pipe
snprintf(buf2, sizeof buf2, "%s%s%s", "fifopipes/",senderlogin,".fifo");
if((fdanuluj = open(buf2, O_WRONLY)) == -1){
perror("openFdanuluj");
exit(EXIT_FAILURE);
}
//SEND MESSAGE TO CLIENT
snprintf(buf3, sizeof buf3, "%s%s", "serwer ", "end");
if((write(fdanuluj, buf3, strlen(buf3))) == -1){
perror("writeFdanuluj");
}
close(fdanuluj);
}
}
else if(strcmp(komenda,"/w")==0){
//RECEIVER LOGIN
char receiverlogin[80];
token = strtok(NULL, " ");
printf("%s\n",token);
strcpy(receiverlogin, token);
int r;
char *login;
char *message;
r = splitstring(reszta,(int)strlen(token)+1,&login,&message);
if(r!=1){
printf("error\n");
}
else{
//RECEIVE INFORMATION
login[strlen(receiverlogin)]='\0';
printf("from %s to %s: %s and length is %d \n", senderlogin, login, message, (int)strlen(message));
//OPEN CLIENT PIPE
snprintf(buf2, sizeof buf2, "%s%s%s", "fifopipes/",receiverlogin,".fifo");
if((fd = open(buf2, O_WRONLY))== -1){
perror("openFd");
exit(EXIT_FAILURE);
}
//SEND MESSAGE TO CLIENT
snprintf(buf3, sizeof buf3, "%s%s%s", senderlogin," ",message);
if( (write(fd, buf3, strlen(buf3) )) == -1){
perror("writeopenfd");
}
close(fd);
}
}
}
}
}
close(fdserwer);
}
unlink(buf);
}
void clientchild(char *login)
{
int fd;
char readbuf[80];
int read_bytes;
char buf[256];
snprintf(buf, sizeof buf, "%s%s%s", "fifopipes/",login,".fifo");
umask(0);
if(mkfifo(buf, 0777) == -1){
perror("mkfifoclient");
exit(EXIT_FAILURE);
}
while(1){
if((fd = open(buf, O_CREAT | O_RDONLY)) == -1){
perror("openFdchild");
exit(EXIT_FAILURE);
}
if((read_bytes = read(fd, &readbuf, sizeof(readbuf))) == -1){
perror("readfdchild");
}
else{
readbuf[read_bytes] = '\0';
//SENDER LOGIN
char nickname[80];
strcpy(nickname, readbuf);
char * token = strtok(nickname, " ");
//printf("%s\n",token);
int r;
char *login;
char *message;
r = splitstring(readbuf,(int)strlen(token)+1,&login,&message);
if(r!=1){
printf("blad\n");
}
else{
login[strlen(token)]='\0';
if(strcmp(login,"serwer")==0 && strcmp(message,"end")==0){
printf("Login error. Closing...\n");
close(fd);
break;
}
printf("%s: %s and length is %d \n", login, message, (int)strlen(message));
close(fd);
//printf("Received string: \"%s\" and length is %d \n", readbuf, (int)strlen(readbuf));
}
//free(login);
//free(message);
}
}
unlink(buf);
}
void clientparent(char *login)
{
signal(SIGQUIT,sig_handler_parent);
int fd;
int stringlen;
char readbuf[80];
char buf[256];
char buf2[256];
snprintf(buf, sizeof buf, "%s%s", "fifopipes/","serwer.fifo");
printf("FIFO_CLIENT: Send messages infinitely\n");
while(1){
if((fd = open(buf, O_WRONLY)) == -1){
perror("openFdparent");
exit(EXIT_FAILURE);
}
//printf("Enter string: ");
fgets(readbuf, sizeof(readbuf), stdin);
stringlen = strlen(readbuf);
readbuf[stringlen - 1] = '\0';
snprintf(buf2, sizeof buf2, "%s%s%s", login," ",readbuf);
if(strlen(login)+1 == strlen(buf2)){
printf("Error\n");
break;
}
else{
if((write(fd, buf2, strlen(buf2))) == -1){
perror("writeparent");
}
printf("Sent string: \"%s\" and string length is %d \n", buf2, (int)strlen(buf2));
}
}
close(fd);
}
void splitclient(char *login)
{
printf("login: %s\n", login);
pid_t pid = fork();
printf("fork returned: %d\n", (int) pid);
//signal(SIGCHLD, handler);
if (pid < 0){
perror("Fork failed");
}
else if (pid == 0){
signal(SIGQUIT,sig_handler_child);
printf("I am the child with pid %d\n", (int) getpid());
char buf[256];
snprintf(buf, sizeof buf, "%s%d", "Child ",(int) getpid());
//kod dziecka
clientchild(login);
//kill(getppid(),SIGQUIT);
exit(0);
}
else{
// We must be the parent
printf("I am the parent, waiting for child to end \n");
//kod rodzica
clientparent(login);
pid_t childpid = wait(NULL);
printf("Parent knows child %d finished\n", (int)childpid);
printf("Parent ending...\n");
}
}
int main(int argc, char **argv)
{
while(1)
{
int c;
int option_index = 0;
static struct option long_options[] =
{
{"start", no_argument, NULL, 's'},
{"login", required_argument, NULL, 'l'},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "sl:", long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 's':
printf("start server\n");
startserwer();
break;
case 'l':
printf("login with option %s \n", optarg);
//verifyloginclient(optarg);
splitclient(optarg);
break;
case '?':
break;
default:
abort();
}
}
if (optind < argc)
{
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
putchar ('\n');
}
return 0;
}
From this piece in the code in startServer():
if((read_bytes = read(fdserwer, &readbuf, sizeof(readbuf)))== -1){
perror("readbytes");
}
else{
:
char *token = strtok(senderlogin, " ");
:
strcpy(senderlogin, token);
b = splitstring(readbuf, (int)
strlen(token)+1,&loginnadawcy,&resztakomendy);
You are not validating if token is a non-NULL pointer post tokenization. In the case the child exits, read() would return a 0 (and not -1 as a failure), indicating EOF as the man tells:
RETURN VALUE
On success, the number of bytes read is returned (zero indicates
end of file),
Thus the senderlogin buffer would be empty and wouldn't yield any tokens. You need to factor in this case and have appropriate null checks in place. Adding a null chek will lead to a graceful exit of the server program.
How this program should work:
Make 3 processes, P1 is reading line from keyboard, P2 is checking if the line is looking like this - number1+number2+...+number n, P3 is giving me sum of this equation.
This works fine.
The second part is that I have to use Signals+FIFO to either stop(S1-SIGINT), freeze(S2-SIGUSR1) or resume(S3-SIGUSR2) work in this program. One signal should store the info about what signal was called in FIFO, and then using another signal(S4) tell every other process what to do.
When giving S1 to the process, it sometimes works for 1,2 or 3 processes, when sending S2 to any process, P2 dies, and only P2. I don't know why it works like that.
Yes, i have to use Signals + FIFO.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#define MAX 1000
#define S1 SIGINT
#define S2 SIGUSR1
#define S3 SIGUSR2
#define S4 SIGCONT
#define SIGNAL "\033[1;33m\033[5m>> SIGNAL <<\033[0m\n"
void signal_callback(int signo);
void signal_rcv();
void signal_handling();
int read_line(char text[], int n);
struct msg_buffer {
long msg_type;
char msg_text[100];
} m;
int fd;
char buf[2];
char inter_snd=0, inter_rcv=0, work = 1, quit = 0;
int main()
{
key_t key = ftok(".", 5);
key_t key2 = ftok(",", 4);
int msg_id = msgget(key, 0666 | IPC_CREAT);
int msg_id2 = msgget(key2, 0666 | IPC_CREAT);
mkfifo("/tmp/fifo", 0666);
if(msg_id == -1)
{
perror("msgget");
exit(EXIT_FAILURE);
}
if(msg_id2 == -1)
{
perror("msgget");
exit(EXIT_FAILURE);
}
if(fork()==0)
{
signal(S1, signal_callback);
signal(S2, signal_callback);
signal(S3, signal_callback);
signal(S4, signal_rcv);
do
{
if(read_line(m.msg_text, MAX)!=EOF)
{
if(work)
{
m.msg_type=1;
int length;
length = strlen(m.msg_text);
if(msgsnd(msg_id, &m, sizeof(m),0)==-1)
{
perror("msgsnd");
exit(EXIT_FAILURE);
}
printf("[P1]Sending message.\n");
}
}
}while(1);
exit(0);
}
if(fork()==0)
{
signal(S1, signal_callback);
signal(S2, signal_callback);
signal(S3, signal_callback);
signal(S4, signal_rcv);
do
{
if(work)
{
m.msg_type=1;
if(msgrcv(msg_id, &m, sizeof(m), 1, 0)==-1)
{
perror("msgsnd");
exit(1);
}
else printf("[P2]Receiving message.\n");
int length = strlen(m.msg_text), i=0, plus=0, pass=1;
char check[1];
for(;i<length;i++)
{
check[0]=m.msg_text[i];
if((i == 0 && m.msg_text[0]=='+') || (i == length-1 && m.msg_text[length-1] == '+'))
{
printf("Bad\n");
pass=0;
break;
}
if((check[0]<'0' || check[0]>'9') && check[0] != '+')
{
printf("Bad\n");
pass=0;
break;
}
else if(check[0] == '+')
{
if(plus==1)
{
printf("Bad\n");
pass=0;
break;
}
plus++;
}
else plus =0;
}
if(pass==1)
{
m.msg_type=2;
if(msgsnd(msg_id2, &m, sizeof(m),0)==-1)
{
perror("msgsnd");
}
printf("[P2]Sending message.\n");
}
}
}while(1);
exit(0);
}
if(fork()==0)
{
signal(S1, signal_callback);
signal(S2, signal_callback);
signal(S3, signal_callback);
signal(S4, signal_rcv);
do
{
if(work)
{
m.msg_type=2;
if(msgrcv(msg_id2, &m, sizeof(m), 2, 0)==-1)
{
perror("msgsnd");
}
printf("[P3]Receiving message.\n");
int count=0, i=0,length = strlen(m.msg_text), nr=0, sum=0;
char check[1];
int numbers[20];
for(; i<length; i++)
{
check[0]= m.msg_text[i];
if(check[0] == '+')
{
char number[20];
strncpy(number, m.msg_text+(i-count), count);
number[count] = '\0';
int a = atoi(number);
numbers[nr] = a;
nr++;
count =0;
}
count++;
}
{
char number[20];
strncpy(number, m.msg_text+(i-count), count);
number[count] = '\0';
int a = atoi(number);
numbers[nr] = a;
nr++;
count =0;
}
i=0;
for(;i<nr; i++)
{
sum += numbers[i];
}
printf("Sum: %d\n", sum);
}
}while(1);
exit(0);
}
wait(NULL);
wait(NULL);
wait(NULL);
printf("Program end.\n");
msgctl(msg_id, IPC_RMID, NULL);
msgctl(msg_id2, IPC_RMID, NULL);
remove("/tmp/fifo");
}
int read_line(char text[], int n)
{
char *ptext;
int return_value;
int length;
ptext = fgets(text, n, stdin);
if(ptext == NULL)
{
return_value = EOF;
}
else
{
length = strlen(text);
if(length>0 && text[length-1]=='\n') text[length-1]='\0';
return_value=1;
}
return return_value;
}
void signal_callback(int signo)
{
//printf("%sSignal %d in PID %d\n", SIGNAL, signo, (int)getpid());
inter_snd = signo;
signal_handling();
}
void signal_rcv()
{
//printf("cos");
fd=open("/tmp/fifo", O_RDWR);
if(read(fd, &inter_snd, sizeof(char)))
{
//printf("przeczytal");
}
//printf("inter_snd = %d\n", inter_snd);
switch (inter_snd)
{
case S1:
//printf("%d Quitting...\n", (int)getpid());
_exit(0);
break;
case S2:
//printf("%d Stopping...\n", (int)getpid());
work = 0;
break;
case S3:
//printf("%d Starting...\n", (int)getpid());
work = 1;
break;
default: break;
//printf("There's garbage in memory :/..\n");
}
}
void signal_handling(void)
{
if (inter_snd>0)
{
//printf("Signal received...\n");
fd = open("/tmp/fifo", O_RDWR);
write(fd, &inter_snd, sizeof(char));
write(fd, &inter_snd, sizeof(char));
write(fd, &inter_snd, sizeof(char));
inter_snd = 0;
//printf("Sending to other processes\n");
kill(0, S4);
}
}
(Used non-async functions just to let me see what is happening)
The child_filter has to read values from pipefd and write these in a named pipe.
The problem is that if i try to un-comment the comment[3] (the open of the named-pipe) the function won't print values, it seem to be stuck on read() call. Instead, if i do not open the fifo pipe it works.
I need named pipe for other stuffs.
What shall i modify? Maybe pipe and named-pipe conflicts using them together?
Thanks.
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFONAME "./my-fgrep-named-pipe"
typedef struct{
int i;
int v;
int word;
int filename;
char word_string[250];
char filename_string[250];
}parameters;
int pipefd[2];
void child_reader(parameters params){
FILE* fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
if(params.filename==0)
fp = stdin;
else
fp = fopen(params.filename_string, "r");
close(pipefd[0]); /* Close unused read end */
if (fp != NULL){
while ((read = getline(&line, &len, fp)) != -1) {
//printf("Retrieved line of length %zu :\n", read);
//printf("%s", line);
write(pipefd[1], line, strlen(line));
}
fclose(fp);
}
free(line);
printf("child reader > end\n");
exit(0);
}
void child_filter(parameters params){
char c;
char temp[250];
int i=0;
char *temp2;
int fifofd;
close(pipefd[1]); /* Close unused write pipe end */
printf("read from pipe\n");
if( (fifofd = open(FIFONAME, O_WRONLY)) == -1) printf("Error WW\n");
while (read(pipefd[0], &c, 1) > 0){
if (c == '\n' || c == '\r'){
temp[i] = '\n';
if(i>0){
temp2=strtok(temp, "\n");
//temp2[i] = '\n';
// printf("[%s]\n", temp2);
write(fifofd, temp2, strlen(temp2));
}i=0;
}
else{
temp[i] = c;
i++;
}
}
close(fifofd);
printf("child filter > end\n");
exit(0);
}
void child_writer(parameters params){
char c;
int fifofd;
char temp[250];
int i=0;
char *temp2;
if( (fifofd = open(FIFONAME, O_RDONLY)) == -1) printf("Error RR\n");
while (read(fifofd, &c, 1) > 0){
printf("entry > [%c] \n", c);
}
printf("exit-------------\n");
close(fifofd);
unlink(FIFONAME);
exit(0);
}
int main(int argc, char *argv[]){
char* temp1;
parameters params;
int forkResult;
params.i=0;
params.v=0;
params.word=0;
params.filename=0;
int pid_r, pid_w, pid_f;
if(argc<2){
printf("error\n");
exit(0);
}
if(strcmp(argv[1],"-i") == 0)
params.i++;
if(strcmp(argv[1],"-v") == 0)
params.v++;
if(argc>2){
if(strcmp(argv[2],"-i") == 0)
params.i++;
if(strcmp(argv[2],"-v") == 0)
params.v++;
}
if(params.i == 0 && params.v == 0){
params.word++;
strcpy(params.word_string, argv[1]);
if(argc>2){
params.filename++;
strcpy(params.filename_string, argv[2]);
}
}
else if(params.i != 0 && params.v != 0){
if(argc>3){
params.word++;
strcpy(params.word_string, argv[3]);
}
if(argc>4){
params.filename++;
strcpy(params.filename_string, argv[4]);
}
}
else{
if(argc>2){
params.word++;
strcpy(params.word_string, argv[2]);
}
if(argc>3){
params.filename++;
strcpy(params.filename_string, argv[3]);
}
}
printf("Result: i[%d], v[%d], name[%d], filename[%d]\n", params.i, params.v, params.word, params.filename);
if(params.word==0){
printf("Error X\n");
exit(0);
}
if (pipe(pipefd) == -1) {
printf("pipe error\n");
exit(0);
}
unlink(FIFONAME);
if( mkfifo(FIFONAME, 0666) != 0) printf("Error fifo1\n");
if( (pid_r=fork()) == 0 ){
child_reader(params);
}
if( (pid_f=fork()) == 0 ){
child_filter(params);
}
if( (pid_w=fork()) == 0 ){
child_writer(params);
}
waitpid(pid_r, NULL, 0);
printf("Reader finished\n");
close(pipefd[1]);
waitpid(pid_f, NULL, 0);
close(pipefd[0]);
printf("filter finished\n");
waitpid(pid_w, NULL, 0);
printf("Done!\n");
exit(0);
}
If you open a named pipe for writing then it'll block until the other end is opened for reading. That's an expected behaviour.
I need named pipe for other stuffs
Well, if there's no one reading from the pipe then what other stuff can you do with the write end of the pipe? So, you have to ensure there's a reader from the pipe or delay opening the pipe until there's someone ready to read from it. One other option is to open with O_RDWR.
The problem was that forks dupe file descriptors and so they were still opened.
Due to this reason, child process won't finish.
Fixed code:
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFONAME "./my-fgrep-named-pipe"
typedef struct{
int i;
int v;
int word;
int filename;
char word_string[250];
char filename_string[250];
}parameters;
int pipefd[2];
void child_reader(parameters params){
FILE* fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
if(params.filename==0)
fp = stdin;
else
fp = fopen(params.filename_string, "r");
close(pipefd[0]); /* Close unused read end */
if (fp != NULL){
while ((read = getline(&line, &len, fp)) != -1) {
//printf("Retrieved line of length %zu :\n", read);
//printf("%s", line);
write(pipefd[1], line, strlen(line));
}
fclose(fp);
}
free(line);
close(pipefd[1]); /* Close unused read end */
printf("child reader > done\n");
exit(0);
}
void child_filter(parameters params){
char c;
char temp[250];
int i=0;
char *temp2;
int fifofd;
close(pipefd[1]); /* Close unused write pipe end */
if( (fifofd = open(FIFONAME, O_WRONLY)) == -1) printf("Error fifoWW\n");
printf("read from pipe\n");
while (read(pipefd[0], &c, 1) > 0){
if (c == '\n' || c == '\r'){
temp[i] = '\n';
if(i>0){
temp2=strtok(temp, "\n");
//temp2[i] = '\n';
//printf("[%s]\n", temp2);
write(fifofd, temp2, strlen(temp2)); //prima senza +1;
}i=0;
}
else{
temp[i] = c;
i++;
}
}
close(fifofd);
close(pipefd[0]);
printf("child filter > done\n");
exit(0);
}
void child_writer(parameters params){
char c;
char temp[250];
int i=0;
char *temp2;
int size;
int fifofd;
if( (fifofd = open(FIFONAME, O_RDONLY)) == -1) printf("Error fifoRR\n");
do{
printf("entry> [%c] \n", c);
size = read(fifofd, &c, 1);
printf("next size read> %d\n", size);
}while(size > 0);
close(fifofd);
printf("exit-------------\n");
//unlink(FIFONAME);
exit(0);
}
int main(int argc, char *argv[]){
char* temp1;
parameters params;
int esitoFork;
params.i=0;
params.v=0;
params.word=0;
params.filename=0;
int pid_r, pid_w, pid_f;
FILE *myfifo;
if(argc<2){
printf("error \n");
exit(0);
}
if(strcmp(argv[1],"-i") == 0)
params.i++;
if(strcmp(argv[1],"-v") == 0)
params.v++;
if(argc>2){
if(strcmp(argv[2],"-i") == 0)
params.i++;
if(strcmp(argv[2],"-v") == 0)
params.v++;
}
if(params.i == 0 && params.v == 0){ // [3] ho il nome, [4] ho il filename
params.word++;
strcpy(params.word_string, argv[1]);
if(argc>2){
params.filename++;
strcpy(params.filename_string, argv[2]);
}
}
else if(params.i != 0 && params.v != 0){ // [2] ho il nome, [3] ho il filename
if(argc>3){
params.word++;
strcpy(params.word_string, argv[3]);
}
if(argc>4){
params.filename++;
strcpy(params.filename_string, argv[4]);
}
}
else{ // [3] ho il nome, [4] ho il filename
if(argc>2){
params.word++;
strcpy(params.word_string, argv[2]);
}
if(argc>3){
params.filename++;
strcpy(params.filename_string, argv[3]);
}
}
printf("Result: i[%d], v[%d], nome[%d], filename[%d]\n", params.i, params.v, params.word, params.filename);
if(params.word==0){
printf("Error syntax\n");
exit(0);
}
if (pipe(pipefd) == -1) {
printf("pipe error\n");
exit(0);
}
if( mkfifo(FIFONAME, 0666) != 0) printf("Error fifo\n");
if( (pid_r=fork()) == 0 ){
child_reader(params);
}
if( (pid_f=fork()) == 0 ){
child_filter(params);
}
close(pipefd[0]);
close(pipefd[1]);
if( (pid_w=fork()) == 0 ){
child_writer(params);
}
waitpid(pid_r, NULL, 0);
printf("Reader finished\n");
waitpid(pid_f, NULL, 0);
printf("filter finished\n");
waitpid(pid_w, NULL, 0);
printf("Done!\n");
unlink(FIFONAME);
exit(0);
}
I have three threads - the first one reads sentences until ";" is given, the second counts the characters in those sentences, and the third shows the result.
Well, I've done this for only one sentence, but sending arrays through pipes seems to generate some problems (as well as reading multiple strings from a thread).
For reading, I can put the string only once, and no more. Even mutex on the whole function doesn't work. Why is that so?
Also, after writing the string I get "write: Success" message.
What's wrong here?
This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/stat.h>
#include <pthread.h>
#include <string.h>
int first[2];
int second[2];
void *input(void *ptr)
{
char str[100], ch = '0';
int length, i = 0;
while(1)
{
while(ch != ';')
{
printf("Enter the %d message: ", i + 1);
fflush(stdout);
length = read(STDIN_FILENO, str, sizeof(str));
if(write(first[1], str, sizeof(str)) != length)
{
perror("write");
exit(2);
}
if(length <= 0)
{
if(length == -1)
perror("read");
close(first[1]);
exit(2);
}
i++;
}
}
}
void *countChars(void *ptr)
{
char str[100];
int length, count = 0, i = 0;
while(1)
{
length = read(first[0], str, sizeof(str));
if(length <= 0)
{
if(length == -1)
perror("read");
close(first[0]);
close(second[1]);
exit(2);
}
if(write(STDOUT_FILENO, str, length) != length)
{
perror("write");
exit(2);
}
while(str[count] != '\n') count++;
write(second[1], &count, sizeof(count));
count = 0;
}
}
void *output(void *ptr)
{
int length, count = 0, i = 0;
while(1)
{
length = read(second[0], &count, sizeof(count));
if(length < sizeof(count))
{
close(second[0]);
exit(2);
}
printf("Number of characters: %d\n", count);
}
}
int main()
{
pthread_t t1, t2, t3;
if(pipe(first) == -1)
{
printf("First pipe error");
exit(1);
}
if(pipe(second) == -1)
{
printf("Second pipe error");
exit(1);
}
pthread_create(&t1, NULL, input, NULL);
pthread_create(&t2, NULL, countChars, NULL);
pthread_create(&t3, NULL, output, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
return 0;
}
EDIT.
I think the question would be - how to logically solve this? I see it that way:
Thread1 -> (string) -> Thread2 -> (number of chars) -> Thread3 - save elements somewhere
...
Thread1 -> (ending string) -> Thread2 -> (number of chars removed later) -> Thread3 - display all elements
BUT if so then - how to make threads run one by one like this? How to stop the application on ending string? Where to save those integer values in thread 3?
Pipes are used to communicate data between processes, not threads. Threads run in the same process and have access to the same memory so it is pointless to use pipes in that case.
An example of a pipeline with three processes. Parent sends "hello world" to child, who prepends the string length and sends that new string to the grandchild who prints it to stdout.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void parent(int fd_write) {
char *msg = "hello world";
ssize_t len = strlen(msg);
if (write(fd_write, msg, len) != len) {perror("parent write"); exit(1);}
}
void child(int fd_read, int fd_write) {
char msg_in[100], msg_out[150];
ssize_t len = read(fd_read, msg_in, sizeof msg_in);
if (len == -1) {perror("child read"); exit(1);}
msg_in[len] = '\0';
len = sprintf(msg_out, "%d: %s", (int)len, msg_in);
if (write(fd_write, msg_out, len) != len) {perror("child write"); exit(1);}
}
void grandchild(int fd_read) {
char msg[256];
ssize_t len = read(fd_read, msg, sizeof msg);
if (len == -1) {perror("grandchild read"); exit(1);}
msg[len] = '\0';
printf("Msg: %s\n", msg);
}
int main() {
enum {READ, WRITE};
pid_t pid;
int fd[2];
if (pipe(fd) == -1) {perror("first pipe"); exit(1);}
pid = fork();
if (pid == -1) {perror("first fork"); exit(1);}
if (pid == 0) {
int fd2[2];
if (pipe(fd2) == -1) {perror("second pipe"); exit(1);}
pid = fork();
if (pid == -1) {perror("second fork"); exit(1);}
if (pid == 0) {
close(fd2[WRITE]);
grandchild(fd2[READ]);
close(fd2[READ]);
exit(0);
}
close(fd[WRITE]); close(fd2[READ]);
child(fd[READ], fd2[WRITE]);
close(fd[READ]); close(fd2[WRITE]);
wait(NULL);
exit(0);
}
close(fd[READ]);
parent(fd[WRITE]);
close(fd[WRITE]);
wait(NULL);
return 0;
}
In the input thread, after the read call length = read(STDIN_FILENO, str, sizeof(str));, you are writing sizeof(str) and not of size length.
It should be
if(write(first[1], str, length) != length)
Another issue is your code is not matching your specification.
You say that input thread is reading until ';', but ch is never modified in the loop. Fix your code.
I have three threads - the first one reads a string, the second counts characters, and the third displays it. I'm using pipes for communication.
However, after running it nothing happens, and when I type in something, let's say "asd", I get:
asd
asd
Enter the message: Enter the message:
or
asd
asd
Enter the message:
What's wrong?
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/stat.h>
#include <pthread.h>
#include <string.h>
int first[2];
int second[2];
void *input(void *ptr)
{
char str[100];
int length;
while(1)
{
printf("Enter the message: ");
length = read(STDIN_FILENO, str, sizeof(str));
if(length <= 0)
{
if(length == -1)
perror("read");
close(first[1]);
exit(2);
}
if(write(first[1], str, length) != length)
{
perror("write");
exit(2);
}
}
}
void *countChars(void *ptr)
{
char str[100];
int length, count = 0;
while(1)
{
length = read(first[0], str, sizeof(str));
if(length <= 0)
{
if(length == -1)
perror("read");
close(first[0]);
close(second[1]);
exit(2);
}
if(write(STDOUT_FILENO, str, length) != length)
{
perror("write");
exit(2);
}
while(str[count] != '\n') count++;
write(second[1], &count, sizeof(count));
count = 0;
}
}
void *output(void *ptr)
{
int length, count = 0;
while(1)
{
length = read(second[0], &count, sizeof(count));
if(length <= sizeof(count))
{
close(second[0]);
exit(2);
}
printf("Number of characters: %d\n", count);
}
}
int main()
{
pthread_t t1, t2, t3;
if(pipe(first) == -1)
{
printf("First pipe error");
exit(1);
}
if(pipe(second) == -1)
{
printf("Second pipe error");
exit(1);
}
pthread_create(&t1, NULL, input, NULL);
pthread_create(&t2, NULL, countChars, NULL);
pthread_create(&t3, NULL, output, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
return 0;
}
You have a logic problem in your code. In output:
if (length < sizeof (count)) { // not <=
length will always equal sizeof (count) on successful write of an integer.
Also, wrapping everything function in while (1) {...} is not the safest. Remove the while (1) loops and replace them with a return at the end of the function. i.e. return ptr; For example:
void *
output (void *ptr) {
int length, count = 0;
printf ("\noutput:\n\n");
// while (1) {
length = read (second[0], &count, sizeof (count));
printf ("count: %d\n", count);
if (length < sizeof (count)) { // not <=
printf ("closing second[0] and exiting\n");
close (second[0]);
exit (2);
}
printf ("Number of characters: %d\n", count);
// }
return ptr;
}
That's because printf only writes content to buffer. The content will be actually sent to stdout once it receives a line feed ('\n') or fflush(stdout) is called.
You can try to add flush(stdout); next to the printf("Enter the message: ");, and you should see what you expect.