一.信号量
进化版的互斥锁(1---->N)
由于互斥锁的粒度比较大,如果我们希望多个线程间对某个对象的部分数据进行共享【类似于行锁,拥有部分是不一样的】,使用互斥锁是没有办法实现的,只能讲整个对象锁住,这样虽然保证了多个线程操作同一个共享资源数据的正确性,但同时也降低了 线程的并发程度。线程从并行执行变为串行执行,与直接用单进程操作该数据速度还要慢些,为什么呢? 因为锁 也是一种资源,上锁和 解锁 也是有开销的。
信号量是一种相对折中的方式,即能保证同步,数据不紊乱,也能保证线程/进程的并发性
二.信号量的主要应用函数
- sem _init,函数
- sem_destroy函数
- sem_wait函数
- sem_trywait函数
- sem_timedwait函数
- sem_post函数
以上6个函数的返回值都是:成功返回0,失败返回-1,同时设置errno。(注意,它们没有pthread前缀==>进程也可以用)
sem_t类型,本质仍是结构体。但应用期间可简单看作为整数,忽略实现细节(类似于使用文件描述符)
sem_t sem:规定信号量sem不能<0。头文件<semaphore.h>
三.信号量基本操作:
sem -wait: 1.信号量大于0,则信号量--(类比 pthread_mutex_lock) 2.信号量等于0,造成线程阻塞
l
对应
l
sem_post:将信号量++,同时唤醒阻塞在信号量上的线程(类比pthread_mutex_unlock)但,由于sem_t的实现对用户隐藏,所以所谓的++、--操作只能通过函数来实现,而不能直接++、--符号。信号量的初值,决定了占用信号量的线程的个数。
四.信号量函数详解
1.sem_ init函数初始化一个信号量
int sem_init(sem_t*sem, int pshared,unsigned int value);
- 参1: sem信号量
- 参2: pshared,取0用于线程间;取非0(一般为1)用于进程间
- 参3: value指定信号量初值
2.sem_destroy函数销毁一个信号量
int sem_destroy(sem_t*sem);
3.sem wait函数给信号量加锁--
int sem _wait(sem_ t *sem);
4.sem post函数给信号量解锁++
int sem post(sem _t *sem);
五.代码Demo【生产者 消费者 信号量模型】
#include <iostream>
#include <semaphore.h>
#include <unistd.h>
#include <time.h>
using namespace std;
#define THREAD_NUM 8
sem_t sem_blank, sem_star;
int queue[THREAD_NUM];
void*
prod_func(void* arg)
{
int i = THREAD_NUM;
int index = 0;
while(i--){
sem_wait(&sem_blank);
queue[index] = rand()%THREAD_NUM + 1;
printf("-----productor----- %d \n", queue[index]);
sem_post(&sem_star);
index = (index+1) % THREAD_NUM;
sleep(rand()%2+1);
}
pthread_exit(NULL);
}
void*
cons_func(void* arg)
{
int i = THREAD_NUM;
int index = 0;
while(i--){
sem_wait(&sem_star);
printf("-----consumer----- %d \n", queue[index]);
queue[index] = 0;
sem_post(&sem_blank);
index = (index+1) % THREAD_NUM;
sleep(rand()%3);
}
pthread_exit(NULL);
}
int
main(int argc, char*argv[])
{
pthread_t prod_tid, cons_tid;
sem_init(&sem_blank, 0, THREAD_NUM);
sem_init(&sem_star, 0, 0);
srand(time(NULL));
pthread_create(&prod_tid, NULL, prod_func, NULL);
pthread_create(&cons_tid, NULL, cons_func, NULL);
pthread_join(prod_tid, NULL);
pthread_join(cons_tid, NULL);
sem_destroy(&sem_blank);
sem_destroy(&sem_star);
pthread_exit(NULL);
}
原理图