1、前言
最近看了一些QoS的实现原理,大致分为漏桶模型、令牌桶模型。特别是令牌桶,什么双桶双速三色概念都比较复杂还得慢慢理解,但对于单桶单速,就开始怎么进行原型实现了。
需求上看的话,多线程版本可以直接拿一个变量实现,但是多进程版本的话,就得考虑进程间问题了。
2、原理
Linux进程间共享的变量,于是想到了POSIX信号量semaphore
,提供了整型计数器,调用者可进行获取、释放的PV操作,常用于标识资源是否可用,若信号量变为0,进行P接口调用将进入阻塞。
A semaphore is an integer whose value is never allowed to fall below zero. Two operations can be performed on semaphores: increment the
semaphore value by one (sem_post(3)); and decrement the semaphore value by one (sem_wait(3)). If the value of a semaphore is currently
zero, then a sem_wait(3) operation will block until the value becomes greater than zero.
2.1 有名信号量
有名信号量支持进程间使用,在 /dev/shm
下创建信号量文件,
Named semaphores
A named semaphore is identified by a name of the form /somename; that is, a null-terminated string of up to NAME_MAX-4 (i.e., 251)
characters consisting of an initial slash, followed by one or more characters, none of which are slashes. Two processes can oper‐
ate on the same named semaphore by passing the same name to sem_open(3).
The sem_open(3) function creates a new named semaphore or opens an existing named semaphore. After the semaphore has been opened,
it can be operated on using sem_post(3) and sem_wait(3). When a process has finished using the semaphore, it can use sem_close(3)
to close the semaphore. When all processes have finished using the semaphore, it can be removed from the system using
sem_unlink(3).
2.2 匿名信号量
匿名信号量是基于内存的信号量,常用于多线程间、或亲缘关系的多进程场景(如fork出来的父子进程)
Unnamed semaphores (memory-based semaphores)
An unnamed semaphore does not have a name. Instead the semaphore is placed in a region of memory that is shared between multiple
threads (a thread-shared semaphore) or processes (a process-shared semaphore). A thread-shared semaphore is placed in an area of
memory shared between the threads of a process, for example, a global variable. A process-shared semaphore must be placed in a
shared memory region (e.g., a System V shared memory segment created using shmget(2), or a POSIX shared memory object built cre‐
ated using shm_open(3)).
Before being used, an unnamed semaphore must be initialized using sem_init(3). It can then be operated on using sem_post(3) and
sem_wait(3). When the semaphore is no longer required, and before the memory in which it is located is deallocated, the semaphore
should be destroyed using sem_destroy(3).
3. 实践
3.1 编程
主要思路是实现一个令牌生产者,每秒以恒定的速率生产令牌;
然后消费者每次就必须获取到令牌了才能do_something
,令牌不足时就进行阻塞等待;
生产者代码,使用sem_open
以读写形式打开信号量,
循环中使用 sem_getvalue
sem_post
进行生产:
void token_generate()
{
int nums = 0;
struct timeb tb = {
0