进程同步

进程同步
使用fork系统调用创建进程
  • fork系统调用是用于创建进程的
  • fork创建的进程初始化状态与父进程一样
  • 系统会为fork的进程分配新的资源
  • fork系统调用无参数
  • fork会返回两次,分别返回子进程id和0
  • 返回子进程id的是父进程,返回0的是子进程
#include 
#include 
#include 
#include 

using namespace std;

int main()
{
    // 进程id
    pid_t pid;

    int num = 888;
    pid = fork();

    if(pid == 0){
        cout << "这是一个子进程." << endl;
        cout << "num in son process: " << num << endl;
        while(true){
            num += 1;
            cout << "num in son process: " << num << endl;
            sleep(1);
        }
    } else if(pid > 0){
        cout << "这是一个父进程." << endl;
        cout << "子进程id: " << pid << endl;
        cout << "num in father process: " << num << endl;
        while(true){
            num -= 1;
            cout << "num in father process: " << num << endl;
            sleep(1);
        }
    } else if (pid < 0){
        cout << "创建进程失败." << endl;
    }
    return 0;
}
共享内存

进程默认是不能访问进程空间之外的内存空间的,但是在分配进程空间时可以让多个进程同时指向同一块内存空间

进程同步_第1张图片
image.png

共享内存是两个进程之间共享和传递数据最快的方式,但是共享内存也有其缺点,它未提供同步机制,需要借助其它机制管理访问

步奏

  • 申请共享内存
  • 连接到进程空间
  • 使用共享内存
  • 脱离进程空间 & 删除

common.h

#ifndef __COMMON_H__
#define __COMMON_H__

#define TEXT_LEN 2048

// 共享内存的数据结构
struct ShmEntry{
    // 是否可以读取共享内存,用于进程间同步
    bool can_read;
    // 共享内存信息
    char msg[2048]; 
};

#endif

clinet.cpp

#include "common.h"

#include 
#include 
#include 
#include 
#include 

#include 

int main()
{
    struct ShmEntry *entry;

    // 1. 申请共享内存
    int shmid = shmget((key_t)1111, sizeof(struct ShmEntry), 0666|IPC_CREAT);
    if (shmid == -1){
        std::cout << "Create share memory error!" << std::endl;
        return -1;
    }

    // 2. 连接到当前进程空间/使用共享内存
    entry = (ShmEntry*)shmat(shmid, 0, 0);
    entry->can_read = 0;
    char buffer[TEXT_LEN];
    while (true){
        if (entry->can_read == 0){
            std::cout << "Input message>>> ";
            fgets(buffer, TEXT_LEN, stdin);
            strncpy(entry->msg, buffer, TEXT_LEN);
            std::cout << "Send message: " << entry->msg << std::endl;
            entry->can_read = 1;
        }
    }
    // 3. 脱离进程空间
    shmdt(entry);

    // 4. 删除共享内存 
    shmctl(shmid, IPC_RMID, 0);

    return 0;
}

server.cpp

#include "common.h"

#include 
#include 
#include 
#include 
#include 

#include 

int main()
{
    // 共享内存的结构体
    struct ShmEntry *entry;

    // 1. 申请共享内存
    int shmid = shmget((key_t)1111, sizeof(struct ShmEntry), 0666|IPC_CREAT);
    if (shmid == -1){
        std::cout << "Create share memory error!" << std::endl;
        return -1;
    }

    // 2. 连接到当前进程空间/使用共享内存
    entry = (ShmEntry*)shmat(shmid, 0, 0);
    entry->can_read = 0;
    while (true){
        if (entry->can_read == 1){
            std::cout << "Received message: " << entry->msg << std::endl;
            entry->can_read = 0;
        }else{
            std::cout << "Entry can not read. Sleep 1s." << std::endl;
            sleep(1);
        }
    }
    // 3. 脱离进程空间
    shmdt(entry);

    // 4. 删除共享内存 
    shmctl(shmid, IPC_RMID, 0);

    return 0;
}
Unix域套接字
  • 域套接字是一种高级的进程间通信的方法
  • Unix域套接字可以用于同一机器进程间通信
  • 套接字(socket)原始网络通信中使用的术语
  • Unix系统提供的域套接字提供了网络套接字类似的功能

Server

创建套接字 -- 绑定套接字 -- 监听套接字 -- 接收处理信息

Client

创建套接字 -- 连接套接字 -- 发送信息

Server.cpp

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 

// 域套接字
#define SOCKET_PATH "./domainsocket"
#define MSG_SIZE 2048

int main()
{
    int socket_fd, accept_fd;
    int ret = 0;
    socklen_t addr_len;
    char msg[MSG_SIZE];
    struct sockaddr_un server_addr;

    // 1. 创建域套接字
    socket_fd = socket(PF_UNIX,SOCK_STREAM,0);
    if(-1 == socket_fd){
        std::cout << "Socket create failed!" << std::endl;
        return -1;
    }
    // 移除已有域套接字路径
    remove(SOCKET_PATH);
    // 内存区域置0
    bzero(&server_addr,sizeof(server_addr));
    server_addr.sun_family = PF_UNIX;
    strcpy(server_addr.sun_path, SOCKET_PATH);

    // 2. 绑定域套接字
    std::cout << "Binding socket..." << std::endl;
    ret = bind(socket_fd,(sockaddr *)&server_addr,sizeof(server_addr));

    if(0 > ret){
        std::cout << "Bind socket failed." << std::endl;
        return -1;
    }
    
    // 3. 监听套接字
    std::cout << "Listening socket..." << std::endl;
    ret = listen(socket_fd, 10);
    if(-1 == ret){
        std::cout << "Listen failed" << std::endl;
        return -1;
    }
    std::cout << "Waiting for new requests." << std::endl;
    accept_fd = accept(socket_fd, NULL, NULL);
    
    bzero(msg,MSG_SIZE);

    while(true){
        // 4. 接收&处理信息
        recv(accept_fd, msg, MSG_SIZE, 0);
        std::cout << "Received message from remote: " << msg <

client.cpp

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 

#define SOCKET_PATH "./domainsocket"
#define MSG_SIZE 2048

int main()
{
    int socket_fd;
    int ret = 0;
    char msg[MSG_SIZE];
    struct sockaddr_un server_addr;

    // 1. 创建域套接字
    socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
    if(-1 == socket_fd){
        std::cout << "Socket create failed!" << std::endl;
        return -1;
    }
    
    // 内存区域置0
    bzero(&server_addr,sizeof(server_addr));
    server_addr.sun_family = PF_UNIX;
    strcpy(server_addr.sun_path, SOCKET_PATH);

    // 2. 连接域套接字
    ret = connect(socket_fd, (sockaddr *)&server_addr, sizeof(server_addr));

    if(-1 == ret){
        std::cout << "Connect socket failed" << std::endl;
        return -1;
    }

    while(true){
        std::cout << "Input message>>> ";
        fgets(msg, MSG_SIZE, stdin);
        // 3. 发送信息
        ret = send(socket_fd, msg, MSG_SIZE, 0);
    }

    close(socket_fd);
    return 0;
}

你可能感兴趣的:(进程同步)