条件变量(Condition Variable)和信号量(Semaphore)是两种不同的同步原语,尽管它们都用于线程间协调,但设计目标、使用方式和适用场景有本质区别。以下是关键对比:
核心区别总结
特性 | 条件变量 (Condition Variable) | 信号量 (Semaphore) |
---|---|---|
本质 | 无状态,依赖外部条件判断 | 有状态(整数计数器) |
操作对象 | 必须绑定一个互斥锁(Mutex)使用 | 独立操作 |
唤醒机制 | 需手动通知(notify ) | 自动释放(post 增加计数) |
等待行为 | wait() 会释放锁并阻塞 | wait() (或 P() )阻塞 |
典型用途 | 等待特定条件成立(如“队列非空”) | 控制资源访问数量(如限流) |
关于条件变量的使用,参看往期文章:https://www.madbull.site/?p=672,在 pthread_pool 项目中,主要是使用 条件变量 实现任务的处理,可以从这篇文章下载源码查看。
今天记录一下信号量的使用方法,代码如下:
// gcc sem.c -lpthread -o sem
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#define BUFFER_SIZE 5 // 缓冲区大小
#define NUM_ITEMS 10 // 每个生产者生产的项目数量
// 共享缓冲区
int buffer[BUFFER_SIZE];
int in = 0; // 生产者插入位置
int out = 0; // 消费者取出位置
// 信号量
sem_t empty; // 空槽位信号量
sem_t full; // 满槽位信号量
sem_t mutex; // 互斥信号量(保护缓冲区)
// 生产者线程函数
void* producer(void* arg) {
int producer_id = *((int*)arg);
for (int i = 0; i < NUM_ITEMS; i++) {
// 生产一个项目(模拟耗时)
int item = rand() % 100;
sem_wait(&empty); // 等待空槽位(P操作)
sem_wait(&mutex); // 进入临界区(保护缓冲区)
// 将项目放入缓冲区
buffer[in] = item;
printf("生产者 %d 生产: %d (位置: %d)\n", producer_id, item, in);
in = (in + 1) % BUFFER_SIZE;
sem_post(&mutex); // 离开临界区
sem_post(&full); // 增加满槽位(V操作)
usleep(rand() % 100000); // 随机睡眠
}
return NULL;
}
// 消费者线程函数
void* consumer(void* arg) {
int consumer_id = *((int*)arg);
for (int i = 0; i < NUM_ITEMS; i++) {
sem_wait(&full); // 等待满槽位(P操作)
sem_wait(&mutex); // 进入临界区(保护缓冲区)
// 从缓冲区取出项目
int item = buffer[out];
printf("消费者 %d 消费: %d (位置: %d)\n", consumer_id, item, out);
out = (out + 1) % BUFFER_SIZE;
sem_post(&mutex); // 离开临界区
sem_post(&empty); // 增加空槽位(V操作)
// 消费项目(模拟耗时)
usleep(rand() % 150000); // 随机睡眠
}
return NULL;
}
int main() {
pthread_t prod_thread1, prod_thread2;
pthread_t cons_thread1, cons_thread2;
int prod_id1 = 1, prod_id2 = 2;
int cons_id1 = 1, cons_id2 = 2;
// 初始化信号量
sem_init(&empty, 0, BUFFER_SIZE); // 初始空槽位数 = 缓冲区大小
sem_init(&full, 0, 0); // 初始满槽位数 = 0
sem_init(&mutex, 0, 1); // 互斥信号量初始为1(二进制信号量)
// 创建生产者线程
pthread_create(&prod_thread1, NULL, producer, &prod_id1);
pthread_create(&prod_thread2, NULL, producer, &prod_id2);
// 创建消费者线程
pthread_create(&cons_thread1, NULL, consumer, &cons_id1);
pthread_create(&cons_thread2, NULL, consumer, &cons_id2);
// 等待线程结束
pthread_join(prod_thread1, NULL);
pthread_join(prod_thread2, NULL);
pthread_join(cons_thread1, NULL);
pthread_join(cons_thread2, NULL);
// 销毁信号量
sem_destroy(&empty);
sem_destroy(&full);
sem_destroy(&mutex);
printf("所有生产和消费完成!\n");
return 0;
}
编译测试:

发表回复