1.头文件-semaphore.h
2.信号量类型
- sem_t sem;
- 加强版的互斥锁
3.主要函数
- 初始化信号量
em_init(sem_t *sem,int pshared,unsigned int value);
0-线程同步
1-进程同步
value-最多有几个线程操作共享数据
- 销毁信号量
sem_destroy(sem_t *sem);
- 加锁
sem_wait(sem_t *sem);
调用一次相当于对sem做了一次 -- 操作
如果sem值为0,线程会阻塞
- 尝试加锁
sem_trywait(sem_t *sem);
sem == 0;加锁失败,不阻塞,直接发
- 限时尝试加锁
sem_timewait(sem_t *sem,xxxx);
- 解锁++
sem_post(sem_t *sem);
对sem做了++ 操作
4.练习
使用信号量实现生产者,消费者模型。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
sem_t producer_sem;
sem_t customer_sem;
typedef struct node
{
int data;
struct node* next;
}Node;
Node* head = NULL;
void* producer(void* arg)
{
while(1)
{
sem_wait(&producer_sem); //-- =0
Node* node = (Node*)malloc(sizeof(Node));
node->data = rand()%1000;
node->next = head;
head = node;
printf("producer:%ld,%d\n",pthread_self(),node->data);
sem_post(&customer_sem); //customer_sem ++
sleep(rand()%5);
}
return NULL;
}
void* customer(void* arg)
{
while(1)
{
sem_wait(&customer_sem); //0
Node* del = head;
head = head->next;
printf("customer:%ld,%d\n",pthread_self(),del->data);
free(del);
sem_post(&producer_sem); //producer ++
sleep(rand()%5);
}
return NULL;
}
int main()
{
pthread_t thid[2];
sem_init(&producer_sem,0,4);
sem_init(&customer_sem,0,0);
pthread_create(&thid[0],NULL,producer,NULL);
pthread_create(&thid[1],NULL,customer,NULL);
for(int i = 0;i < 2;i++)
{
pthread_join(thid[i],NULL);
}
sem_destroy(&producer_sem);
sem_destroy(&customer_sem);
return 0;
}
①先告诉你:这代码在干嘛?
- 生产者:生产节点,插入链表
- 消费者:消费节点,删除链表
- 限制 :链表最多存 4 个节点(满了就不能生产)
- 实现 :用 信号量 控制生产、消费的节奏
②先讲核心:什么是信号量?
信号量 = 一个计数器 + 等待队列
两个最核心操作:
-
sem_wait( sem )
- 计数器 -1
- 如果计数器 < 0,线程阻塞等待
-
sem_post( sem )
- 计数器 +1
- 如果有等待的线程,唤醒一个
③两个信号量的作用
sem_t producer_sem; // 表示"空闲位置",最多4个
sem_t customer_sem; // 表示"已有产品数量",初始0
- producer_sem = 4 → 链表最多放 4 个节点
- customer_sem = 0 → 一开始链表空的,没有产品
④main函数初始化信号量
sem_init(&producer_sem, 0, 4);
sem_init(&customer_sem, 0, 0);
- 第 1 个参数:信号量变量
- 第 2 个参数:0 = 线程间使用
- 第 3 个参数:初始值
⑤生产者线程
void* producer(void* arg)
{
while(1)
{
sem_wait(&producer_sem); // 空闲位置 -1
sem_wait(&producer_sem)
-
空闲位置 减 1
-
如果减到 < 0 → 生产者阻塞(链表满了,不能再生产)
// 生产节点 Node* node = (Node*)malloc(sizeof(Node)); node->data = rand()%1000; node->next = head; head = node; printf("producer:%ld,%d\n",pthread_self(),node->data); sem_post(&customer_sem); // 产品数量 +1
sem_post(&customer_sem)
-
产品数量 +1
-
唤醒等待的消费者
sleep(rand()%5); } return NULL;}
⑥消费者线程
void* customer(void* arg)
{
while(1)
{
sem_wait(&customer_sem); // 产品数量 -1
sem_wait(&customer_sem)
-
产品数量 -1
-
如果 < 0 → 消费者阻塞(链表空,没的消费)
// 消费(头删节点) Node* del = head; head = head->next; printf("customer:%ld,%d\n",pthread_self(),del->data); free(del); sem_post(&producer_sem); // 空闲位置 +1
sem_post(&producer_sem)
-
空闲位置 +1
-
唤醒阻塞的生产者
sleep(rand()%5); } return NULL;}
⑦整段代码运行流程
初始状态
producer_sem = 4customer_sem = 0
第 1 步
消费者执行 sem_wait(customer)→ 0-1 = -1 → 阻塞等待
第 2 步
生产者生产sem_wait(producer) → 4-1=3生产完sem_post(customer) → 0+1=1
第 3 步
消费者被唤醒消费完sem_post(producer) → 3+1=4
第 4 步
如果生产者连续生产 4 次producer_sem 变成 0第 5 次生产时 sem_wait → 阻塞
⑧这个代码实现了什么?
-
链表最多存 4 个节点
-
满了,生产者就等
-
空了,消费者就等
-
生产一个,才能消费一个
-
完全用信号量实现同步

| 版本 | 输出特点 | 核心问题 |
|---|---|---|
| 无锁版本 | 生产、消费乱序,数字错乱、丢失 | 线程不安全,数据竞争 |
| 互斥锁 + 条件变量版本 | 生产一个、消费一个,严格交替,无连续生产 / 消费 | 缓存为 0,生产后必须等消费,效率低 |
| 信号量版本(当前) | 可连续生产(最多 4 个)、连续消费,一一对应 | 带缓存的生产者 - 消费者,效率更高 |