简体   繁体   中英

How to send arrays between threads using pipes?

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.

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