进程间通信(信号量)

一 原理

1. 和共享内存/消息队列一样都属于system v版本的进程间通信,接口大同小异。

2. 还是和之前的共享内存/消息队列一样,通过形成的key_t并创建一个信号量集,一个信号量集里面可以有多个信号量,并初始化信号量集合,后续对集合中某个特定的元素进行操作。

3. 信号量主要用来计数器,信号量++,--操作是原子的,自带同步机制,当某个信号量元素为0则阻塞/其他时间,阻塞有资源则就唤醒等。

二 接口

1. semget

#include 
#include 
#include 

int semget(
            key_t key,   // ftok的返回值 
            int nsems,   // 信号量集合里的信号量的个数
            int semflg   // 怎么创建/权限是什么
          );

2. semctl

#include 
#include 
#include 

int semctl(
            int semid,    // semget的返回值
            int semnum,   // 信号量集中某个元素的小标 , 0 ~ n
            int cmd,      // 怎么操作这个对应的下标的元素 
            ...           // 元素类型 -> 看下面
          );

union semun
{
     int val;               /* Value for SETVAL */
     struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */
     unsigned short *array; /* Array for GETALL, SETALL */
     struct seminfo *__buf; /* Buffer for IPC_INFO
                                      (Linux-specific) */
}

3. semop

#include 
#include 
#include 

int semop(
            int semid,            // semget的返回值
            struct sembuf *sops,  // 信号集里面的某个元素
            size_t nsops          // 信号集里元素的个数
         );

struct sembuf{
               unsigned short sem_num;  // 元素的下标
               short          sem_op;   // 怎么操作
               short          sem_flg;  // 不满足条件触发的功能
             }

三 二元信号量的demo代码 

#pragma once
#include 
#include 
#include 
#include 
#include 

const std::string key_path = "/home/CD/linux/Semaphore";
const int key_val = 123;

int Create = IPC_CREAT | IPC_EXCL | 0666;
int User = IPC_CREAT;

// 转16进制
void To_Hex(int val)
{
    char buff[1024] = {0};
    snprintf(buff, sizeof(buff), "0x%x", val);
    std::cout << buff << std::endl;
    return;
}

// 获取 key_t
key_t Getkey(const std::string &mypath, int myproj)
{
    key_t key = ftok(mypath.c_str(), myproj);
    return key;
}

class Semaphore
{
public:
    Semaphore()
    {
        create_key();
    }
    // 释放信号量
    ~Semaphore()
    {
        if (_semid != -1)
        {
            if (semop(_semid, 0, IPC_RMID) == -1)
            {
                std::cout << " delete Semaphore failed" << std::endl;
                exit(3);
            }
        }
    }
    void P()
    {
        // 设置某个信号量元素的 -- 操作
        sembuf sem;
        sem.sem_num = 0;
        sem.sem_op = -1;
        int n = semop(_semid, &sem, _nums);
        if (n == -1)
        {
            std::cout << "P semop set failed" << std::endl;
            exit(2);
        }
    }
    void V()
    {
        // 设置某个信号量元素的 ++ 操作
        sembuf sem;
        sem.sem_num = 0;
        sem.sem_op = 1;
        int n = semop(_semid, &sem, _nums);
        if (n == -1)
        {
            std::cout << "V semop set failed" << std::endl;
            exit(2);
        }
    }
    
    // 创建/获取信号量     信号量集合的个数  初始值
    void identity(int flag, int nums, int val = -1)
    {
        _nums = nums;
        if (flag == IPC_CREAT | IPC_EXCL | 0666)
        {
            _semid = semget(_key, nums, flag);
            if (_semid == -1)
            {
                std::cout << "msgget failed" << std::endl;
                exit(2);
            }
            std::cout << "create sem success" << std::endl;
            sem_init_nums(_nums, val);
        }
        else if (flag == IPC_CREAT)
        {
            _semid = semget(_key, nums, flag);
            if (_semid == -1)
            {
                std::cout << "msgid get failed" << std::endl;
                exit(2);
            }
        }
    }

private:
    // 获取key_t
    void create_key()
    {
        _key = Getkey(key_path, key_val);
        if (_key == -1)
        {
            std::cout << "key_t failed" << std::endl;
            exit(1);
        }
        std::cout << "key_t success" << std::endl;
    }
    // 初始化信号量集合的每个元素的初始值
    void sem_init_nums(int nums, int val)
    {
        if (_nums <= 0)
        {
            std::cout << "_nums<=0" << std::endl;
            exit(3);
        }
        union semun
        {
            int val;               
            struct semid_ds *buf;  
            unsigned short *array; 
            struct seminfo *__buf; 
        } sem;
        sem.val = val;
        for (int i = 0; i < _nums; i++)
        {
            semctl(_semid, i, SETVAL, sem);
        }
    }

private:
    key_t _key;
    int _semid;
    int _nums;
};

你可能感兴趣的:(Linux(操作系统),linux)