【问题标题】:How can 2 processes talk to each other without pipe()?两个进程如何在没有 pipe() 的情况下相互通信?
【发布时间】:2012-07-06 14:02:18
【问题描述】:

鉴于此代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

#define BUF_SIZE 256

int main()
{
    int fd1[2];
    int fd2[2];

    ssize_t numRead = -1;

    // remark : working under the assumption that the messages are of equal length

    const char* messageOne = "Hello world , I'm child number 1\n";
    const char* messageTwo = "Hello world , I'm child number 2\n";

    const unsigned int commLen = strlen(messageOne) + 1;

    char buf[BUF_SIZE];

    if (pipe(fd1) == -1)
    {
        printf("Error opening pipe 1!\n");
        exit(1);
    }

    if (pipe(fd2) == -1)
    {
        printf("Error opening pipe 2!\n");
        exit(1);
    }

    printf("Piped opened with success. Forking ...\n");

    // child 1
    switch (fork())
    {
        case -1:
            printf("Error forking child 1!\n");
            exit(1);

        case 0:
            printf("\nChild 1 executing...\n");
            /* close reading end of first pipe */
            if (close(fd1[0]) == -1)
            {
                printf("Error closing reading end of pipe 1.\n");
                _exit(1);
            }
            /* close writing end of second pipe */
            if (close(fd2[1]) == -1)
            {
                printf("Error closing writing end of pipe 2.\n");
                _exit(1);
            }

            /* write to pipe 1 */
            if (write(fd1[1], messageOne, commLen) != commLen)
            {
                printf("Error writing to pipe 1.\n");
                _exit(1);
            }

            if (close(fd1[1]) == -1)
            {
                printf("Error closing writing end of pipe 1.\n");
                _exit(1);
            }

            /* reding from pipe 2 */
            numRead = read(fd2[0], buf, commLen);
            if (numRead == -1)
            {
                printf("Error reading from pipe 2.\n");
                _exit(1);
            }

            if (close(fd2[0]) == -1)
            {
                printf("Error closing reding end of pipe 2.\n");
                _exit(1);
            }

            printf("Message received child ONE: %s", buf);
            printf("Exiting child 1...\n");
            _exit(0);
            break;

        default:
            break;
    }

    // child 2
    switch (fork())
    {
        case -1:
            printf("Error forking child 2!\n");
            exit(1);
        case 0:
            printf("\nChild 2 executing...\n");
            /* close reading end of second pipe */
            if (close(fd2[0]) == -1)
            {
                printf("Error closing reading end of pipe 2.\n");
                _exit(1);
            }
            /* close writing end of first pipe */
            if (close(fd1[1]) == -1)
            {
                printf("Error closing writing end of pipe 1.\n");
                _exit(1);
            }

            /* read from the first pipe */
            if (read(fd1[0], buf, commLen) == -1)
            {
                printf("Error reading from pipe 1.\n");
                _exit(EXIT_FAILURE);
            }

            if (close(fd1[0]) == -1)
            {
                printf("Error closing reading end of pipe 1.\n");
                _exit(EXIT_FAILURE);
            }

            /* write to the second pipe */
            if (write(fd2[1], messageTwo, commLen) != commLen)
            {
                printf("Error writing to the pipe.");
                _exit(EXIT_FAILURE);
            }

            if (close(fd2[1]) == -1)
            {
                printf("Error closing writing end of pipe 2.");
                _exit(EXIT_FAILURE);
            }

            printf("Message received child TWO: %s", buf);
            printf("Exiting child 2...\n");
            _exit(EXIT_SUCCESS);
            break;

        default:
            break;
    }

    printf("Parent closing pipes.\n");

    if (close(fd1[0]) == -1)
    {
        printf("Error closing reading end of the pipe.\n");
        exit(EXIT_FAILURE);
    }

    if (close(fd2[1]) == -1)
    {
        printf("Error closing writing end of the pipe.\n");
        exit(EXIT_FAILURE);
    }

    if (close(fd2[0]) == -1)
    {
        printf("Error closing reading end of the pipe.\n");
        exit(EXIT_FAILURE);
    }

    if (close(fd1[1]) == -1)
    {
        printf("Error closing writing end of the pipe.\n");
        exit(EXIT_FAILURE);
    }

    printf("Parent waiting for children completion...\n");
    if (wait(NULL) == -1)
    {
        printf("Error waiting.\n");
        exit(EXIT_FAILURE);
    }

    if (wait(NULL) == -1)
    {
        printf("Error waiting.\n");
        exit(EXIT_FAILURE);
    }

    printf("Parent finishing.\n");
    exit(EXIT_SUCCESS);
}

这是两个使用 pipe() 的进程之间的简单对话。

输出是:

Piped opened with success. Forking ...
Parent closing pipes.
Parent waiting for children completion...

Child 2 executing...

Child 1 executing...
Message received child TWO: Hello world , I'm child number 1
Exiting child 2...
Message received child ONE: Hello world , I'm child number 2
Exiting child 1...
Parent finishing.

从上面可以看出,两个孩子正在使用forkpipe 与另一个说话。但是我想在没有管道的情况下做到这一点,这可能吗?如果是这样,请解释如何,我不想使用 pipe() ,我想要 simulate pipe()

谢谢

【问题讨论】:

  • 为什么要这样做?使用pipe() 有什么问题?
  • 您可以使用mkfifo。但这实际上只是调用pipe 的一种更复杂的方式。
  • @robert:我想在没有mkfifo()pipe() 的情况下这样做

标签: c linux pipe named-pipes


【解决方案1】:

虽然我不知道您为什么要这样做,但还有一些其他 IPC 机制(都更复杂,更容易出错):

  • 命名管道 (FIFO)
  • 共享内存
  • 映射的共享内存
  • UNIX 域套接字
  • 互联网域套接字

有关这些方面的优秀教程,请查看“进程间通信”一章中的这本电子书:Advanced Linux Programming

【讨论】:

    【解决方案2】:

    我已经修改了您的程序,以显示 System V 共享内存的示例。为了避免比赛 条件信号量(POSIX 命名信号量)也被使用。我也写了一些cmets。 PL。看看这个例子是否有帮助。 可以参考各个功能的手册页以了解有关功能的更多信息。编译标志应该是 -lpthread。要生成密钥(引用唯一的共享内存段),现有文件(我将其命名为“anyfile”)应该在当前目录中可用,因为我使用了 ftok 函数。 PL。通过检查添加适当的错误处理 函数的返回值。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/shm.h>
    #include <semaphore.h>
    
    #define BUF_SIZE 256
    int main()
    {
        key_t key;
        char *virtualaddr;
        sem_t *get, *put;
        ssize_t numRead = -1;
        int shmid;
    
       const char* messageOne = "Hello world , I'm child number 1\n";
       const char* messageTwo = "Hello world , I'm child number 2\n";
    
       const unsigned int commLen = strlen(messageOne) + 1;
       char buf[BUF_SIZE];
    
       key = ftok("anyfile",'R');
    
      shmid = shmget(key,1024,0644|IPC_CREAT);
      if (0 > shmid)
      {
        perror("Shared Mem creation error\n");
        exit(1);
    
      }
    //Attaching  the shared mem to my address space(available across fork)
     virtualaddr = shmat(shmid, (void*)0, 0);
      /*Create two POSIX Named Semaphores, get and put and initialising with 0*/
     get = sem_open("/get", O_CREAT|O_RDWR, 0644, 0);
    
     put = sem_open("/put", O_CREAT|O_RDWR, 0644, 0);
    
     // child 1
    switch (fork())
    {
        case -1:
            printf("Error forking child 1!\n");
            exit(1);
        case 0:
            printf("\nChild 1 executing...\n");
        //Referring the semaphores..
        get = sem_open ("/get", O_RDWR);
        put = sem_open ("/put", O_RDWR);
    
        //Child 1 writing in shared mem
            strcpy (virtualaddr, messageOne);
        //Child 1 signalling that now child 2 can write
            sem_post (get);
        //Child1 waiting for Child2 to write..
        sem_wait (put);
        //Child 1 reading from shared mem
        strcpy (buf, virtualaddr);          
        printf("Message received child ONE: %s", buf);
            printf("Exiting child 1...\n");
            _exit(0);
            break;
     default:
            break;
    }
    // child 2
    switch (fork())
    {
        case -1:
            printf("Error forking child 2!\n");
            exit(1);
        case 0:
            printf("\nChild 2 executing...\n");
        //Referring the semaphores..
        get = sem_open ("/get", O_RDWR);
        put = sem_open ("/put", O_RDWR);
    
        //Waiting Till Child 1 has written.
            sem_wait (get);
            //Now child 2 can read from shared memory
        strcpy (buf, virtualaddr);
        //Child 2 writing in shared mem
        strcpy (virtualaddr,messageTwo );
        //Signalling that now Child 1 can read.
        sem_post (put);                            
            printf("Exiting child 2...\n");
        printf("Message received child TWO: %s", buf);
            _exit(EXIT_SUCCESS);
            break;
    
        default:
            break;
    }
    printf("Parent waiting for children completion...\n");
    
    if (wait(NULL) == -1)
    {
        printf("Error waiting.\n");
        exit(EXIT_FAILURE);
    }
    
    if (wait(NULL) == -1)
    {
        printf("Error waiting.\n");
        exit(EXIT_FAILURE);
    }
    
    printf("Parent finishing.\n");
    //Deleting semaphores..
    sem_unlink ("/get");
    sem_unlink ("/put");
    //Deleting Shared Memory.
    shmctl (shmid, IPC_RMID, NULL);
    exit(EXIT_SUCCESS);
    

    }

    【讨论】:

      【解决方案3】:

      您可以使用共享内存或 Unix 套接字。如果管道足够的话,不知道你为什么想要这样做。 shmem 和 sockets 都比较底层。

      【讨论】:

      • unwind 打败了我,但这里有一个链接,带有示例fscked.org/writings/SHM/shm-1.html
      • @unwind: 好的,共享内存可行吗?我的意思是我想要 pipe 的所有东西,但没有 pipe() 。你能解释一下吗?谢谢
      • @ron - 只需使用共享内存作为“数据包”队列。如果队列已满,写入器会等待一段时间并再次尝试。阅读器查看“数据包”是否可用,如果可用,则读取它,否则请等待并重试。为什么不使用管道?
      • @EdHeal:这是作业,我不能使用pipemkfifo 和他们的朋友openclose 等.. 忘了把它放在原帖中。 .. 现在添加。
      【解决方案4】:
      1. Unix 套接字
      2. 共享内存
      3. CORBA
      4. IPC 消息传递(见http://www.cs.cf.ac.uk/Dave/C/node25.html
      5. TCP/IP 甚至 UDP
      6. 甚至可以写入文件并使用信号量对其进行标记以供其他进程读取。

      就在我的头顶

      【讨论】:

      • 好吧,我看到了,你们都选择了shared memory。您可以向我展示任何关于此的好例子吗?我在网上查看了一些代码示例,但没有什么具体的......谢谢
      猜你喜欢
      • 2017-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-23
      • 2017-03-16
      相关资源
      最近更新 更多