一 原理
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;
};