操作系统实验——进程通信(FIFO、shared memory)

参考原文链接

共享内存

编译指令:

gcc shared_memory.cpp -I/usr/local/include/ -L/usr/local/lib -lrt -o shared_mem

代码:

/**
 * Sample code for sharing memory between processes
 * Two processes will iteratively increase a counter which values stored in a shared memory
 * 
 */

#include <stdio.h>
#include <unistd.h> // for fork()

#include <sys/mman.h> // for shared memory created
#include <sys/stat.h> // for mode constants
#include <fcntl.h> // for O_* constant

#define SHARED_OBJ_NAME "/somename"

// shared data struct
struct message
{
    int pid;
    int counter;
};

bool write_message(int pid, int value)
{
    int shmFd = shm_open(SHARED_OBJ_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    ftruncate(shmFd, sizeof(message));  
    message *msg_ptr = (message*)mmap(NULL, sizeof(message), PROT_READ | PROT_WRITE, MAP_SHARED, shmFd, 0);
    
    printf("Process %d: Increase the counter.\n", pid);
    msg_ptr->pid = pid;
    msg_ptr->counter = value;

    munmap(msg_ptr, sizeof(message));

    // remember to close to not hit an error of
    // opening too many files
    close(shmFd);

    return true;
}

bool read_message(int curr_pid, int &curr_value)
{
    int shmFd = shm_open(SHARED_OBJ_NAME, O_RDWR, S_IRUSR | S_IWUSR);
    ftruncate(shmFd, sizeof(message));
    message *msg_ptr = (message*)mmap(NULL, sizeof(message), PROT_READ | PROT_WRITE, MAP_SHARED, shmFd, 0);

    if (msg_ptr->pid == curr_pid)
    {
        printf("Process %d: No new msg available.\n", curr_pid);
        return false;
    }
    else
    {
        printf("Process %d: Receive %d from PID %d.\n", curr_pid, msg_ptr->counter, msg_ptr->pid);
        curr_value = msg_ptr->counter;
        munmap(msg_ptr, sizeof(message));
    }

    close(shmFd);

    return true;
}

int main(int argc, char **argv)
{
    printf("Init the initial value.\n");
    write_message(-1, 0);

    // create a child process by calling folk, 
    // it returns a non-zero pid for parent process and 0 for child process created
    pid_t pid = fork();

    //--- PARENT PROCESS
    if (pid != 0)
    {
        for (int i = 0; i < 5; i++)
        {
            int value;
            // only write message if reading sucessfully
            if (read_message(pid, value)) write_message(pid, ++value);
            sleep(0.1);
        }
    }

    //--- CHILD PROCESS
    else
    {
        for (int j = 0; j < 5; j++)
        {
            int value;
            if (read_message(pid, value)) write_message(pid, ++value);
            sleep(0.1);
        }
    }

    printf("=========== End of process %d\n", pid);
    //shm_unlink(SHARED_OBJ_NAME);

    return 0;
}

运行结果:

Init the initial value.
Process -1: Increase the counter.
Process 440735: Receive 0 from PID -1.
Process 440735: Increase the counter.
Process 440735: Receive 2 from PID 0.
Process 440735: Increase the counter.
Process 440735: No new msg available.
Process 440735: No new msg available.
Process 440735: Receive 4 from PID 0.
Process 440735: Increase the counter.
=========== End of process 440735
Init the initial value.
Process -1: Increase the counter.
Process 0: Receive 1 from PID 440735.
Process 0: Increase the counter.
Process 0: Receive 3 from PID 440735.
Process 0: Increase the counter.
Process 0: Receive 5 from PID 440735.
Process 0: Increase the counter.
Process 0: No new msg available.
Process 0: No new msg available.
=========== End of process 0

FIFO

编译指令:

gcc fifo.cpp -I/usr/local/include/ -L/usr/local/lib -lrt -o fifo
/**
 * Example for using named pipe for communicating between processes
 * This demo is for a unidirectional named pipe which transfer data in one direction
 */

#include "csapp.h"

#define NAMED_PIPE "/var/lock/pipename"

// shared data struct
struct message
{
    int pid;
    int counter;
};


int main(int argc, char **argv)
{
    // create the named pipe (fifo) with permission
    int ret = mkfifo(NAMED_PIPE, 0666);
    if (ret < 0)
        printf("Error when creating FIFO. %s\n", strerror(errno));

    // create a child process by calling folk, 
    // it returns a non-zero pid for parent process and 0 for child process created
    pid_t pid = fork();

    //--- the parent process will write to the pipe only
    if (pid != 0)
    {
        int fd = open(NAMED_PIPE, O_WRONLY);
        for (int i = 0; i < 5; i++)
        {
            message msg;
            msg.pid = pid;
            msg.counter = i;
            printf("Process %d: Write %d.\n", pid, i);
            ret = write(fd, &msg, sizeof(msg));
            if (ret < 0)
                printf("Process %d: Error while writing message. %s\n", pid, strerror(errno));
            sleep(0.1);
        }
        close(fd);
    }

    //-- child process will read only
    else
    {
        int fd = open(NAMED_PIPE, O_RDONLY);
        for (int i = 0; i < 5; i++)
        {
            message msg;
            ret = read(fd, &msg, sizeof(msg));
            if (ret < 0)
                printf("Process %d: Error while reading message. %s\n", pid, strerror(errno));
            printf("Process %d: Received value %d from the parent process %d.\n", pid, msg.counter, msg.pid);
            sleep(0.1);
        }
        close(fd);
    }

    unlink(NAMED_PIPE);

    return 0;
}

运行结果:

Process 424351: Write 0.
Process 424351: Write 1.
Process 424351: Write 2.
Process 424351: Write 3.
Process 424351: Write 4.
Process 0: Received value 0 from the parent process 424351.
Process 0: Received value 1 from the parent process 424351.
Process 0: Received value 2 from the parent process 424351.
Process 0: Received value 3 from the parent process 424351.
Process 0: Received value 4 from the parent process 424351.

消息队列

使用消息队列的步骤,定义消息结构->创建消息队列->通过消息队列向进程A发送消息->通过消息队列接收进程A的消息。
每条消息都有一个标识或“类型”,以便进程可以选择适当的消息,并且进程必须共享一个公共“密钥”才能首先获得对队列的访问权限。
进程可以从队列发送或接收消息,队列必须通过msgget()操作初始化,发送和接收消息分别由msgsnd( )和msgrcv()函数执行。

下面的程序实现父进程和子进程之间C/S方式的通信。

#include "csapp.h"

struct mesg_buffer { 
    long mesg_type; 
    char mesg_text[100]; 
} message; 
  
int main(int argc, char **argv) { 
  
    pid_t pid = fork();
    
    if (pid != 0) { 
        key_t key; 
        int msgid; 
        // generate unique key 
        key = ftok("somefile", 65); 

        msgid = msgget(key, 0666 | IPC_CREAT); 
        message.mesg_type = 1; 
    
        printf("Insert message : "); 
       // scanf("%s", message.mesg_text);
        fgets(message.mesg_text, 100, stdin);
        // send message 
        msgsnd(msgid, &message, sizeof(message), 0); 
        // display the message 
        printf("Message sent to server : %s\n", message.mesg_text); 
    } else {
        key_t key; 
        int msgid; 
        // generate unique key 
        key = ftok("somefile", 65); 
        msgid = msgget(key, 0666 | IPC_CREAT); 
        
        printf("Waiting for a message from client...\n");
        // receive message 
        msgrcv(msgid, &message, sizeof(message), 1, 0); 
        // display the message 
        printf("Message received from client : %s \n", message.mesg_text);
        // to destroy the message queue ;
        msgctl(msgid, IPC_RMID, NULL); 
    }
  
    return 0; 
}

编译、运行指令:

$ gcc msgqueue.cpp -I/usr/local/include/ -L/usr/local/lib -o msgque
$ ./msgque
使用stdin输入:
$ hello world!
posted @ 2022-11-02 21:12  Coldarra  阅读(258)  评论(0)    收藏  举报