由于互斥锁的粒度比较大,如果我们希望在多个线程间对某一对象的部分数据进行共享,使用互斥锁是没有办法实现的,只能将整个数据对象锁住。这样虽然达到了多线程操作共享数据时保证数据正确性的目的,却无形中导致线程的并发性下降。线程从并行执行,变成了串行执行。与直接使用单进程无异。信号量,是相对折中的一种处理方式,既能保证同步,数据不混乱,又能提高线程并发。
作用:初始化一个信号量
- int sem_init(sem_t *sem, int pshared, unsigned int value);
- // 参 1:sem 信号量
- // 参 2:pshared 取 0 用于线程间;取非 0(一般为 1)用于进程间
- // 参 3:value 指定信号量初值
信号量的初值,决定了占用信号量的线程(进程)的个数。
作用:销毁一个信号量
int sem_destroy (sem_t *sem);
作用:给信号量加锁--
int sem_wait(sem_t *sem);
作用:给信号量解锁 ++
int sem_post(sem_t *sem);
作用:尝试对信号量加锁 – (与 sem_wait 的区别类比 lock 和 trylock)
int sem_trywait(sem_t *sem);
作用:限时尝试对信号量加锁 --
- int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
- // 参 2:abs_timeout 采用的是绝对时间。
根据注释,代码还是比较好理解的。两个信号量来控制,一个初始为0,表示一开始生产的数量为0.另外一个初始的数量是可以存放商品的空格数,初始化就是格子数N。
互斥和条件变量的方式是我消费 你不能生产。 而两个信号量是你生产 我可以消费。毕竟环形的不影响,最多你生产了,我不知道。就怕多个生产者 ,你格子放入了还没移到下一个格子我又重复放入了。
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <pthread.h>
- #include <semaphore.h>
-
-
- #define NUM 5
-
- int queue[NUM]; // 全局数组模拟实现环形队列
- sem_t black_number, product_number; // 空格子信号量。产品信号量
-
-
- // 生产者回调函数
- void* producer(void* arg) {
- int i = 0;
- int res = 0;
-
- while (1) {
- // 空格子信号量加锁,将空格数减一,为0则阻塞等待
- res = sem_wait(&black_number);
- if (res != 0) {
- fprintf(stderr, "sem_wait black_number error:%s\n", strerror(res));
- exit(1);
- }
-
- // 模拟生产一个产品
- queue[i] = rand() % 1000 + 1;
- printf("------Produce---%d\n", queue[i]);
-
- // 产品信号量解锁,将产品++
- res = sem_post(&product_number);
- if (res != 0) {
- fprintf(stderr, "sem_post product_number error:%s\n", strerror(res));
- exit(1);
- }
-
- i = (i + 1) % NUM;
- sleep(rand() % 2);
- }
- }
-
-
- // 消费者回调函数
- void* consumer(void* arg) {
- int i = 0;
- int res = 0;
-
- while (1) {
- // 消费者将产品数量--,为0则阻塞等待
- res = sem_wait(&product_number);
- if (res != 0) {
- fprintf(stderr, "sem_wait product_number error:%s\n", strerror(res));
- exit(1);
- }
-
- printf("==============================Consumer=========%d\n", queue[i]);
-
- // 消费一个产品
- queue[i] = 0;
-
- // 消费后将空格数++
- res = sem_post(&black_number);
- if (res != 0) {
- fprintf(stderr, "sem_post black_number error:%s\n", strerror(res));
- exit(1);
- }
-
- // 模拟环形队列
- i = (i + 1) % NUM;
- sleep(rand() % 5);
- }
- }
-
-
- int main(int argc, char** argv) {
- // 生产者线程和消费者线程
- pthread_t pid, cid;
-
- // 初始化空格子信号量,信号量为5,线程间共享----0
- int res = sem_init(&black_number, 0, NUM);
- if (res != 0) {
- fprintf(stderr, "sem_init black_number error:%s\n", strerror(res));
- exit(1);
- }
-
- // 初始化产品信号量,产品数量是0
- res = sem_init(&product_number, 0, 0);
- if (res != 0) {
- fprintf(stderr, "sem_init product_number error:%s\n", strerror(res));
- exit(1);
- }
-
-
- // 创建生产者线程
- res = pthread_create(&pid, NULL, producer, NULL);
- if (res != 0) {
- fprintf(stderr, "pthread_create producer error:%s\n", strerror(res));
- exit(1);
- }
-
- // 创建消费者线程
- res = pthread_create(&cid, NULL, consumer, NULL);
- if (res != 0) {
- fprintf(stderr, "pthread_create consumer error:%s\n", strerror(res));
- exit(1);
- }
-
- // 回收线程
- res = pthread_join(pid, NULL);
- if (res != 0) {
- fprintf(stderr, "pthread_join producer error:%s\n", strerror(res));
- exit(1);
- }
- res = pthread_join(cid, NULL);
- if (res != 0) {
- fprintf(stderr, "pthread_join consumer error:%s\n", strerror(res));
- exit(1);
- }
-
- // 销毁信号量
- res = sem_destroy(&black_number);
- if (res != 0) {
- fprintf(stderr, "sem_destroy black_number error:%s\n", strerror(res));
- exit(1);
- }
-
- res = sem_destroy(&product_number);
- if (res != 0) {
- fprintf(stderr, "sem_destroy product_number error:%s\n", strerror(res));
- exit(1);
- }
-
- return 0;
- }
执行