信号量:
在生产者消费者模型中,对任务数量的记录 就可以使用信号量来做。当信号量的值小于0
时,工作进程或者线程就会阻塞,等待物品到来。当生产者生产一个物品,会将信号量值加1
操作 sem_post(&sem)
。
这是会唤醒在信号量上阻塞的进程或者线程sem_wait(&sem)
,它们去争抢物品。
信号量广泛用于进程或线程间的同步和互斥 ,信号量本质上是⼀个非负的整数计数器 ,它被用来控制对公共资源的访问。
注意:信号量不能保证多线程数据安全问题,要与互斥量配合使用。
cpp
信号量的类型 sem_t
typedef union
{
char __size[__SIZEOF_SEM_T]; //# define __SIZEOF_SEM_T 32
long int __align;
} sem_t;
cpp
int sem_init(sem_t *sem, int pshared, unsigned int value);
- 初始化信号量
- 参数:
- sem : 信号量变量的地址
- pshared : 0 用在线程间 ,非0 用在进程间
- value : 信号量中的值
int sem_destroy(sem_t *sem);
- 释放资源
int sem_wait(sem_t *sem);
- 对信号量加锁,调用一次对信号量的值-1,如果值为0,就阻塞
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
int sem_post(sem_t *sem);
- 对信号量解锁,调用一次对信号量的值+1
int sem_getvalue(sem_t *sem, int *sval);
sem_t psem;
sem_t csem;
sem_init(psem, 0, 8);
sem_init(csem, 0, 0);
producer() {
sem_wait(&psem); // 8 可以生产,然后-1 = 7
sem_post(&csem) // +1
}
customer() {
sem_wait(&csem); // 原来是0,但生产者生产了一个,所以可以消费1个,1-1 = 0
sem_post(&psem) //我需要一个 +1 = 8
}
网络库中的例子:
主线程通过创建一个新线程去创建一个EventLoop的过程
cpp
// 启动当前线程
void Thread::start() // 一个Thread对象就是记录的一个新线程的详细信息
{
started_ = true;
// 信号量的作用是等待新线程的创建完成,以确保线程对象的 tid_ 成员变量被正确设置
// 解释:如果start线程走的快,直接执行到sem_wait(&sem),由于还没有子线程没有给信号量加一 sem_post(&sem),
// 所以就阻塞住了,等待子线程给信号量加一, tid_已经正确设置了,就可以继续执行了
sem_t sem;
sem_init(&sem, false, 0);
// 创建子线程thread_, 就是这个类的线程,采用智能指针+lamda表达式的方式
// 使用智能指针管理子线程生命周期,确保子线程对象销毁时正确回收,避免内存泄漏
thread_ = std::shared_ptr<std::thread>(new std::thread([&](){
// 获取线程的tid值
tid_ = CurrentThread::tid();
// 子线程给信号量+1,解除主线程的sem_wait阻塞
sem_post(&sem);
//开启一个新线程,专门执行该线程函数
func_(); //包含一个eventLoop
}));
// 这里必须等待获取上面新创建线程的tid值
sem_wait(&sem);
}